poj 3468 A Simple Problem with Integers(原来是一道简单的线段树区间修改用来练练splay)
题目链接:http://poj.org/problem?id=3468
题解:splay功能比线段树强大当然代价就是有些操作比线段树慢,这题用splay实现的比线段树慢上一倍。线段树用lazy标记差不多要2s用splay要4s。可以用splay来实现线段树的区间操作更深层次的了解一下splay算是入个门。
#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <cstdio>
using namespace std;
const int M = 1e5 + ;
typedef long long ll;
int pre[M] , ch[M][] , size[M] , root , tot;//分别表示父节点,左右儿子,大小,根节点,总共的节点数。
int key[M];//当前节点对应的权值
int add[M];//类似懒惰标记
ll sum[M];//当前节点包括他以下的节点权值的总和可以理解为子树权值之和加上这个节点的权值
int a[M];
int n , q;
void NewNode(int &r , int fa , int k) {
r = ++tot;
pre[r] = fa;
size[r] = ;
key[r] = k;
add[r] = ;
sum[r] = ;
ch[r][] = ch[r][] = ;
}//标准的初始化节点
void update(int r , int ad) {
if(r == ) return;
add[r] += ad;
key[r] += ad;
sum[r] += (ll)ad * size[r];
}//节点更新
void push_up(int r) {
size[r] = size[ch[r][]] + size[ch[r][]] + ;
sum[r] = sum[ch[r][]] + sum[ch[r][]] + key[r];
}
void push_down(int r) {
if(add[r]) {
update(ch[r][] , add[r]);
update(ch[r][] , add[r]);
add[r] = ;
}
}//一系列类似线段树的操作。
void Rotate(int x , int kind) {
int y = pre[x];
push_down(y);
push_down(x);
ch[y][!kind] = ch[x][kind];
pre[ch[x][kind]] = y;
if(pre[y]) ch[pre[y]][ch[pre[y]][] == y] = x;
pre[x] = pre[y];
ch[x][kind] = y;
pre[y] = x;
push_up(y);
}
void Splay(int r , int goal) {
push_down(r);
while(pre[r] != goal) {
if(pre[pre[r]] == goal) Rotate(r , ch[pre[r]][] == r);
else {
int y = pre[r];
int kind = (ch[pre[y]][] == y);
if(ch[y][kind] == y) {
Rotate(r , !kind);
Rotate(r , kind);
}
else {
Rotate(y , kind);
Rotate(r , kind);
}
}
}
push_up(r);
if(goal == ) root = r;
}//一系列标准的splay的操作
void build(int &x , int l , int r , int fa) {
if(l > r) return ;
int mid = (l + r) >> ;
NewNode(x , fa , a[mid]);
build(ch[x][] , l , mid - , x);
build(ch[x][] , mid + , r , x);
push_up(x);
}
void init() {
root = , tot = ;
ch[root][] = ch[root][] = pre[root] = size[root] = add[root] = sum[root] = key[root] = ;
NewNode(root , , -);
NewNode(ch[root][] , root , -);
build(ch[ch[root][]][] , , n , ch[root][]);
push_up(root);
push_up(ch[root][]);
}//这里之所以要优先建两个点和后面的更新有关
int get_kth(int r , int k) {
push_down(r);
int t = size[ch[r][]] + ;
if(t == k) return r;
else if(t > k) return get_kth(ch[r][] , k);
else return get_kth(ch[r][] , k - t);
}//获得第几大的数
void ADD(int l , int r , int ad) {
Splay(get_kth(root , l) , );
Splay(get_kth(root , r + ) , root);
update(ch[ch[root][]][] , ad);
push_up(ch[root][]);
push_up(root);
}//这里按照常理应该是将第l-1个节点移到根然后再将r+1的节点移到根的右儿子那么(l~r)就是r+1节点的左儿子的sum值由于之前加了两个节点所以变到了l~r+2,毕竟l-1可能为0就是就是根节点处理起来可能会有些不便。当然无视也行,按照个人喜好来就行。
long long query(int l , int r) {
Splay(get_kth(root , l) , );
Splay(get_kth(root , r + ), root);
return sum[ch[ch[root][]][]];
}//区间查询同理
int main() {
while(scanf("%d%d" , &n , &q) == ) {
for(int i = ; i <= n ; i++) scanf("%d" , &a[i]);
init();
while(q--) {
char c[];
scanf("%s" , c);
if(c[] == 'Q') {
int l , r;
scanf("%d%d" , &l , &r);
printf("%lld\n" , query(l , r));
}
else {
int l , r , x;
scanf("%d%d%d" , &l , &r , &x);
ADD(l , r , x);
}
}
}
return ;
}
poj 3468 A Simple Problem with Integers(原来是一道简单的线段树区间修改用来练练splay)的更多相关文章
- POJ.3468 A Simple Problem with Integers(线段树 区间更新 区间查询)
POJ.3468 A Simple Problem with Integers(线段树 区间更新 区间查询) 题意分析 注意一下懒惰标记,数据部分和更新时的数字都要是long long ,别的没什么大 ...
- poj 3468 A Simple Problem with Integers 【线段树-成段更新】
题目:id=3468" target="_blank">poj 3468 A Simple Problem with Integers 题意:给出n个数.两种操作 ...
- 线段树(成段更新) POJ 3468 A Simple Problem with Integers
题目传送门 /* 线段树-成段更新:裸题,成段增减,区间求和 注意:开long long:) */ #include <cstdio> #include <iostream> ...
- POJ 3468 A Simple Problem with Integers(分块入门)
题目链接:http://poj.org/problem?id=3468 A Simple Problem with Integers Time Limit: 5000MS Memory Limit ...
- POJ 3468 A Simple Problem with Integers(线段树功能:区间加减区间求和)
题目链接:http://poj.org/problem?id=3468 A Simple Problem with Integers Time Limit: 5000MS Memory Limit ...
- poj 3468 A Simple Problem with Integers(线段树+区间更新+区间求和)
题目链接:id=3468http://">http://poj.org/problem? id=3468 A Simple Problem with Integers Time Lim ...
- poj 3468 A Simple Problem with Integers 线段树区间加,区间查询和
A Simple Problem with Integers Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://poj.org/problem?i ...
- poj 3468 A Simple Problem with Integers 线段树区间加,区间查询和(模板)
A Simple Problem with Integers Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://poj.org/problem?i ...
- poj 3468:A Simple Problem with Integers(线段树,区间修改求和)
A Simple Problem with Integers Time Limit: 5000MS Memory Limit: 131072K Total Submissions: 58269 ...
随机推荐
- Could not launch "APP_NAME" process launch failed: 4294967295
真机调试忽然遇到这个问题, Could not launch "APP_NAME" process launch failed: 如图所示: 模拟器上能正常调试………… 这个问题还 ...
- MemCached的工具类。获取cached中的所有key
package com.ibs.auth.controller; import java.io.UnsupportedEncodingException; import java.util.Date; ...
- 注解与AOP切面编程实现redis缓存与数据库查询的解耦
一般缓存与数据库的配合使用是这样的. 1.查询缓存中是否有数据. 2.缓存中无数据,查询数据库. 3.把数据库数据插入到缓存中. 其实我们发现 1,3 都是固定的套路,只有2 是真正的业务代码.我们可 ...
- Hadoop 系列(四)—— Hadoop 开发环境搭建
一.前置条件 Hadoop 的运行依赖 JDK,需要预先安装,安装步骤见: Linux 下 JDK 的安装 二.配置免密登录 Hadoop 组件之间需要基于 SSH 进行通讯. 2.1 配置映射 配置 ...
- java并发编程(四)----(JUC)Lock锁初探
首先我们来回忆一下上一节讲过的synchronized关键字,该关键字用于给代码段或方法加锁,使得某一时刻它修饰的方法或代码段只能被一个线程访问.那么试想,当我们遇到这样的情况:当synchroniz ...
- 简洁实用Socket框架DotNettySocket
目录 简介 产生背景 使用方式 TcpSocket WebSocket UdpSocket 结尾 简介 DotNettySocket是一个.NET跨平台Socket框架(支持.NET4.5+及.NET ...
- python 之 前端开发(基本选择器、组合选择器、 交集与并集选择器、序列选择器、属性选择器、伪类选择器、伪元素选择器)
11.3 css 11.31 基本选择器 11.311 id选择器 根据指定的id名称,在当前界面中找到对应的唯一一个的标签,然后设置属性 <!DOCTYPE html> <html ...
- 弃用 wget, 拥抱多线程下载 axel
0x00 事件 对于在 Linux 的下载工具而言,比较常用的就是 wget 或者 curl,吾也一直用 wget 的方式进行网络上的资源下载.偶然发现了 axel 这个支持多线程的下载工具,试用了几 ...
- 史上最全面的SignalR系列教程-4、SignalR 自托管全解(使用Self-Host)-附各终端详细实例
1.概述 通过前面几篇文章 史上最全面的SignalR系列教程-1.认识SignalR 史上最全面的SignalR系列教程-2.SignalR 实现推送功能-永久连接类实现方式 史上最全面的Signa ...
- OpenResty 社区王院生:APISIX 的高性能实践
2019 年 7 月 6 日,OpenResty 社区联合又拍云,举办 OpenResty × Open Talk 全国巡回沙龙·上海站,OpenResty 软件基金会联合创始人王院生在活动上做了&l ...