题目链接: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. cmd与monkey测试

    monkey测试的相关命令 monkey是模拟用户触摸操作,不支持条件判断.monkey命令格式:  启动安卓模拟器/真机 点击运行->输入cmd->进入命令行界面 查看设备连接情况,ad ...

  2. Cassandra之Docker环境实践

    Cassandra简介 Cassandra是一个开源分布式NoSQL数据库系统. 它最初由Facebook开发,用于储存收件箱等简单格式数据,集GoogleBigTable的数据模型与Amazon D ...

  3. 从源码看java线程状态

    关于java线程状态,网上查资料很混乱,有的说5种状态,有的说6种状态,初学者搞不清楚这个线程状态到底是怎么样的,今天我讲一下如何看源码去解决这个疑惑. 直接上代码: public class Thr ...

  4. 准时制生产(Just in Time,JIT)

    准时制生产(Just in Time,JIT)称为及时生产,出自日本丰田.         1.JIT生产方式的管理理念     JIT的基本概念事指在所需要的精确时间内,按所需要的质量和数量,生产所 ...

  5. Java实现调用Bartender控制条码打印机

    官方提供的主要是C#支持. 基于java调用bartender二次开发官方给了一份1998年的J#代码,,,完全用不了,,,百度谷歌搜索万能的网友的答案,发现也没有可参考的.. 最后想到了之前用到了一 ...

  6. 逆向破解之160个CrackMe —— 002-003

    CrackMe —— 002 160 CrackMe 是比较适合新手学习逆向破解的CrackMe的一个集合一共160个待逆向破解的程序 CrackMe:它们都是一些公开给别人尝试破解的小程序,制作 c ...

  7. 建立第一个G2图表

    Step1:引进G2脚本 方法一:引入在线脚本 <script src="https://gw.alipayobjects.com/os/lib/antv/g2/3.4.10/dist ...

  8. MVC+EF Core 完整教程20--tag helper详解

    之前我们有一篇:“动态生成多级菜单”,对使用Html Helper做了详细讲述,并且自定义了一个菜单的 Html Helper: https://www.cnblogs.com/miro/p/5541 ...

  9. 观书有感(摘自12期CSDN)

    CSDN要闻 Visual Studio 将登陆Mac平台 在11月的Connect()上,微软正式发布了Visual Studio For Max预览版,这是微软这一编程工具首次进入苹果平台.Vis ...

  10. c#引用本地dll发布后运行exe错误

    在config 文件夹 configuration 配置节点下面 添加 <runtime> <gcConcurrent enabled="true" /> ...