题目链接: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)的更多相关文章

  1. POJ.3468 A Simple Problem with Integers(线段树 区间更新 区间查询)

    POJ.3468 A Simple Problem with Integers(线段树 区间更新 区间查询) 题意分析 注意一下懒惰标记,数据部分和更新时的数字都要是long long ,别的没什么大 ...

  2. poj 3468 A Simple Problem with Integers 【线段树-成段更新】

    题目:id=3468" target="_blank">poj 3468 A Simple Problem with Integers 题意:给出n个数.两种操作 ...

  3. 线段树(成段更新) POJ 3468 A Simple Problem with Integers

    题目传送门 /* 线段树-成段更新:裸题,成段增减,区间求和 注意:开long long:) */ #include <cstdio> #include <iostream> ...

  4. POJ 3468 A Simple Problem with Integers(分块入门)

    题目链接:http://poj.org/problem?id=3468 A Simple Problem with Integers Time Limit: 5000MS   Memory Limit ...

  5. POJ 3468 A Simple Problem with Integers(线段树功能:区间加减区间求和)

    题目链接:http://poj.org/problem?id=3468 A Simple Problem with Integers Time Limit: 5000MS   Memory Limit ...

  6. poj 3468 A Simple Problem with Integers(线段树+区间更新+区间求和)

    题目链接:id=3468http://">http://poj.org/problem? id=3468 A Simple Problem with Integers Time Lim ...

  7. 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 ...

  8. 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 ...

  9. poj 3468:A Simple Problem with Integers(线段树,区间修改求和)

    A Simple Problem with Integers Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 58269   ...

随机推荐

  1. 【Android Studio】使用 Genymotion 调试出现错误 INSTALL_FAILED_CPU_ABI_INCOMPATI

    RT -- 解决方法参考: https://my.oschina.net/u/242764/blog/375909 http://blog.csdn.net/wjr2012/article/detai ...

  2. 【Android】Android sdk content loader 0%

    前天用 Eclipse 突然遇到了这个问题...重启了好几次都不行,百度了一下,原来之前有不少人遇到过.后来找到了一篇文章,其中的方法二(如下): 方法二(关闭后,拔网线再重启): 如果用最省事的方法 ...

  3. maven私服nexus上传第三方jar包以及下载

    私服是一个特殊的远程仓库,它是架设在局域网内的仓库服务.私服代理广域网上的远程仓库,供局域网内的Maven用户使用.当Maven需要下载构建的使用,它先从私服请求,如果私服上没有的话,则从外部的远程仓 ...

  4. 四、Python基础(1)

    目录 四.Python基础(1) 四.Python基础(1) 1.什么是变量? 一种变化的量,量是记录世界上的状态,变指得是这些状态是会变化的. 2.为什么有变量? 因为计算机程序的运行就是一系列状态 ...

  5. JDK1.8源码分析03之idea搭建源码阅读环境

    序言:上一节说了阅读源码的顺序,有了一个大体的方向,咱们就知道该如何下手.接下来,就要搭建一个方便阅读源码及debug的环境.有助于跟踪源码的调用情况. 目前新开发的项目, 大多数都是基于JDK1.8 ...

  6. RocketMq中网络通信之服务端

    一,Broker服务端入口(NettyServer端) 首先RocketMq网络通信采用的Netty通信.服务端主要集中在Broker中.我们先看一下Broker的启动类BrokerStartup 显 ...

  7. ASP.NET Core MVC 之视图组件(View Component)

    1.视图组件介绍 视图组件是 ASP.NET Core MVC 的新特性,类似于局部视图,但它更强大.视图组件不使用模型绑定,并且仅依赖于调用它时所提供的数据. 视图组件特点: 呈块状,而不是整个响应 ...

  8. IPC机制1

    1.Android IPC简介 Inter-Process Communication的缩写就是IPC,含义是进程间通信或是跨进程间通信,是指两个进程进行交换数据的过程. 进程是什么? 进程在pc上就 ...

  9. oracle常规使用(一)

    目录 特殊sql distinct 项目中遇到表中无主键,但是某个字段不能重复. 需要匹配id串里的内容 批量更新,但是批量成功返回的是-1 时间格式化 行列互转 应用场景 列转行 总结 oracle ...

  10. Jenkins持续集成项目搭建——基于Python Selenium自动化测试

    参考链接:https://www.liaoxuefeng.com/article/1083282007018592 第一步:去官网https://jenkins.io/下载最新的war包 第二步:安装 ...