题目链接: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. 【iOS】tableView:viewForHeaderInSection: 方法未调用

    今天遇到这个问题,即重写的方法 - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)sec ...

  2. 【iOS】Masonry 自动布局 MASViewConstraint.m:207 错误

    问题详情: Assertion failure 报错原因: make.right.equalTo([_imageView superview]).right.with.offset(-); make. ...

  3. go interface衍生的插件化处理

    在设计程序的许多应用场景中我们会遇到大体分为三个阶段的任务流. 第一.入口 一个或多个入口,等待阻塞的.或者主动请求方式的. ============================== 比如任务流需 ...

  4. MRCPv2在电信智能语音识别业务中的应用

    1. MRCPv2协议简介 媒体资源控制协议(Media Resource Control Protocol, MRCP)是一种基于TCP/IP的通讯协议,用于客户端向媒体资源服务器请求提供各种媒体资 ...

  5. Drawable与 Bitmap 转换总结

    极力推荐文章:欢迎收藏 Android 干货分享 阅读五分钟,每日十点,和您一起终身学习,这里是程序员Android Drawable 使用方法详解请看上篇文章. Drawable 使用方法详解 本篇 ...

  6. istio入门教程

    广告 | kubernetes各版本离线安装包 安装 安装k8s 强势插播广告 三步安装,不多说 安装helm, 推荐生产环境用helm安装,可以调参 release地址 如我使用的2.9.1版本 y ...

  7. 4、一个打了鸡血的for循环(增强型for循环)

    对于循环,我们大家应该都不陌生,例如do-while循环,while循环,for循环,今天给大家介绍一个有趣的东西——打了鸡血的for循环(增强型for循环). 首先看代码,了解一下for循环的结构: ...

  8. python3学习-Queue模块

    python标准库中带有一个Queue模块,顾名思义,队列.该模块也衍生出一些基本队列不具有的功能. 我们先看一下队列的方法: put 存数据 get 取数据 empty 判断队列是否为空 qsize ...

  9. 5月29日 Java性能调优指南 读后感

    并行垃圾收集器 串行垃圾收集器 并发标记清除(CMS)垃圾收集器 Garbage First(G1)垃圾收集器 没有深入的学习G1的原理,只是看了大概的思想; SA工具:待学习

  10. 每个程序员都可以「懂」一点 Linux

    提到 Linux,作为程序员来说一定都不陌生.但如果说到「懂」Linux,可能就没有那么多人有把握了.到底用 Linux 离懂 Linux 有多远?如果决定学习 Linux,应该怎么开始?要学到什么程 ...