POJ 3468.A Simple Problem with Integers 解题报告
用树状数组和线段树会比较简单,这里用这道题来学习Splay。
第一次写,代码比较丑
/*
初始化添加一个key值足够大的结点
保证每个需要的结点都有后继
*/
#include <iostream>
#include <cstdio>
#define ll long long
using namespace std; const int MAXN = , INF = 0x7fffffff; struct node {
//需要的记录信息
ll key, val, sum, lazy, Size, Cnt;
//指向儿子和父亲的指针
node *ch[], *pre;
node() {pre = ch[] = ch [] = ; Size = ; key = ;}
node (ll key) : key (key) {pre = ch[] = ch[] = ; Size = , Cnt = , lazy = ;}
void Csize() {
Size = Cnt;
if (ch[] != NULL) Size += ch[]->Size;
if (ch[] != NULL) Size += ch[]->Size;
}
void Csum() {
sum = val;
if (ch[] != NULL) sum += ch[]->sum + ch[]->Size * ch[]->lazy;
if (ch[] != NULL) sum += ch[]->sum + ch[]->Size * ch[]->lazy;
}
} nil (), *NIL = &nil; struct Splay {
node *root, nod[MAXN];
int ncnt;//计算key值不同的结点数,已去重
Splay() {
ncnt = ;
root = & (nod[ncnt++] = node (INF) );
root->pre = NIL;
root->val = root->sum = ;
}
void Push_Down (node *x) {
if (x->lazy != ) {
if (x->ch[] != NULL) x->ch[]->lazy += x->lazy;
if (x->ch[] != NULL) x->ch[]->lazy += x->lazy;
x->val+=x->lazy;
}
x->lazy = ;
} void Update (node *x) {
x->Csize();
x->Csum();
} void Rotate (node *x, int sta) { //单旋转操作,0左旋,1右旋
node *p = x->pre, *g = p->pre;
Push_Down (p), Push_Down (x);
p->ch[!sta] = x->ch[sta];
if (x->ch[sta] != NULL) x->ch[sta]->pre = p;
x->pre = g;
if (g != NIL)
if (g->ch[] == p) g->ch[] = x;
else g->ch[] = x;
x->ch[sta] = p, p->pre = x, Update (p);
if (p == root ) root = x;
} void splay (node *x, node *y) { //Splay 操作,表示把结点x,转到根
for (Push_Down (x) ; x->pre != y;) { //将x的标记往下传
if (x->pre->pre == y) { //目标结点为父结点
if (x->pre->ch[] == x) Rotate (x, );
else Rotate (x, );
}
else {
node *p = x->pre, *g = p->pre;
if (g->ch[] == p)
if (p->ch[] == x)
Rotate (p, ), Rotate (x, );// / 一字型双旋转
else
Rotate (x, ), Rotate (x, );// < 之字形双旋转 else if (p ->ch[] == x)
Rotate (p, ), Rotate (x, );// \ 一字型旋转
else
Rotate (x, ), Rotate (x, ); // >之字形旋转
}
}
Update (x); //维护x结点
}
//找到中序便利的第K个结点,并旋转至结点y的下面。
void Select (int k, node *y) {
int tem ;
node *t ;
for ( t = root; ; ) {
Push_Down (t) ; //标记下传
tem = t->ch[]->Size ;
if (k == tem + ) break ; //找到了第k个结点 t
if (k <= tem)
t = t->ch[] ; //第k个结点在左子树
else
k -= tem + , t = t->ch[] ;//在右子树
}
splay (t, y);
}
bool Search (ll key, node *y) {
node *t = root;
for (; t != NULL;) {
Push_Down (t);
if (t->key > key && t->ch[] != NULL) t = t->ch[];
else if (t->key < key && t->ch[] != NULL) t = t->ch[];
else
break;
}
splay (t, y);
return t->key == key;
}
void Insert (int key, int val) {
if (Search (key, NIL) ) root->Cnt++, root->Size++;
else {
int d = key > root->key;
node *t = & (nod[++ncnt] = node (key) );
Push_Down (root);
t->val = t->sum = val;
t->ch[d] = root->ch[d];
if (root->ch[d] != NULL) root->ch[d]->pre = t;
t->ch[!d] = root;
t->pre = root->pre;
root->pre = t;
root->ch[d] = NULL;
Update (root);
root = t;
}
Update (root);
}
} sp; ll n, m, x;
int main() {
scanf ("%lld %lld", &n, &m);
sp.Insert (, );
sp.Insert (n + , );
for (int i = ; i <= n; i++) {
scanf ("%lld", &x);
sp.Insert (i, x);
}
char cmd;
int l, r;
for (int i = ; i <= m; i++) {
scanf ("\n%c %d %d", &cmd, &l, &r);
sp.Search (l - , NIL);
sp.Search (r + , sp.root);
if (cmd == 'Q') {
node *t = sp.root->ch[]->ch[];
ll ans = t->sum + t->Size * t->lazy;
printf ("%lld\n", ans);
}
if (cmd == 'C') {
ll c;
scanf ("%lld", &c);
sp.root->ch[]->ch[]->lazy += c;
}
}
return ;
}
POJ 3468.A Simple Problem with Integers 解题报告的更多相关文章
- 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(线段树+区间更新+区间求和)
题目链接:id=3468http://">http://poj.org/problem? id=3468 A Simple Problem with Integers Time Lim ...
- 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 ...
- [ACM] poj 3468 A Simple Problem with Integers(段树,为段更新,懒惰的标志)
A Simple Problem with Integers Time Limit: 5000MS Memory Limit: 131072K Total Submissions: 55273 ...
- 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 ...
随机推荐
- -_-#【响应式】matchMedia
谈谈响应式Javascript <!DOCTYPE html> <html> <head> <meta charset="utf-8"&g ...
- (转载)PHP json_encode() 函数介绍
(转载) 在 php 中使用 json_encode() 内置函数(php > 5.2)可以使用得 php 中数据可以与其它语言很好的传递并且使用它. 这个函数的功能是将数值转换成json数据存 ...
- HDU-4902 Nice boat
Nice boat Time Limit: 30000/15000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)Tot ...
- Install Asterisk 11 on Ubuntu 12.04 LTS
http://blogs.digium.com/2012/11/14/how-to-install-asterisk-11-on-ubuntu-12-4-lts/ Last week I put up ...
- MySQL索引原理与慢查询优化
索引目的 索引的目的在于提高查询效率,可以类比字典,如果要查“mysql”这个单词,我们肯定需要定位到m字母,然后从下往下找到y字母,再找到剩下的sql.如果没有索引,那么你可能需要把所有单词看一遍才 ...
- runtime/KVO等面试题
整理中... 1.KVO内部实现原则 回答:1>KVO是基于runtime机制实现的 2>当某个类的对象第一次被观察时,系统就会在运行期动态地创建该类的一个派生类,在这个派生类中重写基类中 ...
- ural 1106. Two Teams 二分图染色
链接:http://acm.timus.ru/problem.aspx?space=1&num=1106 描述:有n(n<=100)个人,每个人有一个或多个朋友(朋友关系是相互的).将其 ...
- ios策略模式应用
策略模式应用大量应用于解决巨型switch-case if-else..... 具体使用方法 : 策略基类(BaseStrategy)包含一个虚算法,所有子类实现虚算法 容器类含有一个指向策略基类的 ...
- centos7免密码登录
2台主机 192.168.30.207 Master 192.168.30.251 Node1 三台主机检查 ~/.ssh 文件夹没有则新建 ssh-keygen -t rsa 一路狂按回车,最终生成 ...
- Javac编译和JIT编译
编译过程 不论是物理机还是虚拟机,大部分的程序代码从开始编译到最终转化成物理机的目标代码或虚拟机能执行的指令集之前,都会按照如下图所示的各个步骤进行: 其中绿色的模块可以选择性实现.很容易看出,上图中 ...