soj 4018upit解题报告 splay经典应用
2012-08-25 01:04
302 查看
时隔一年,终于解决了upit。。。
先给个题目连接:soj:upit
题目大意:
维护一段序列,序列有4种操作:
1.将[A,B]的值统一赋值为X
2.将[A,B]的值每一个都添加X的若干倍,方法为第一个+X,之后的+2X,3X,.....,kX,如此递推
3.在第C个数之前插入数值X
4.求区间[A,B]的和。
具体参考如下:
序列初始长度为N,开始给出这N个数,之后又M个操作,其中N,M<=100,000 ,A,B均合法,X<=100(其实在64位范围就行了),结果在64位整型内。
分析:
这道题是个典型的序列维护的问题,且维护为区间块,有插入操作,需要惰性维护。
splay和块状链表都可以完成这种维护操作。
以下splay解:
①:插入,求和自不必说。。
②:将[A,B]整体赋值的操作,显然在维护的节点上加入两个域即可满足要求。这里记为clear(int),clFlag(bool)标记该子树是否被赋值,如果被赋值则为true
将clear赋值为-INF的时候表示未赋值可以省去变量clFlag
③:整体加法操作:
考虑之前有[A,B]+X,其子树记为R
后来因为R的旋转等因素将[A,B]分割成[A,C] + [C+1,B],这种时候A到C还是每个元素从+X,+2X,...,+kX,而C+1到B的部分则变成了+(k+1)X,....,+(k+m)X了,
也就是+kX+X,....,+kX+mX
其中k为子树[A,C]的节点数,m为[C+1,B]的节点数。
故每个区间由2个域构成,一个是基础的X,一个是附加的kx,分别记为addition和st
④:操作的组合
考虑对区间值进行操作的赋值和整体加法共2种
其组合无非是4种:赋值&赋值,赋值&加法,加法&加法,加法&赋值。
在区间维护的时候(lazy操作),第二次赋值显然要覆盖第一次赋值,先加法后赋值之前的加法也被覆盖
第二次加法累加到第一次加法上即可,还有就是先赋值后加法。
故在维护的时候有四种情况:
1.该节点仅有赋值,则赋值操作。
2.该节点仅有加法,则加法操作。
3.该节点均有,则必然是先赋值后加法,如果是先加法后赋值,则在上次维护的时候加法被赋值覆盖掉,仅剩赋值操作了。
4.均无。
ps:注意lazy操作,update更新sum,size等域的时候,前提是子树的数据sum和size已经是正确的。
在维护函数help的时候,计算保证该节点的sum和size是正确的,由下往上update。
故凡是在向下搜索节点的时候都要help,在伸展操作的时候要update。
注意update的前提,旋转后要先维护在update。
附个代码:
先给个题目连接:soj:upit
题目大意:
维护一段序列,序列有4种操作:
1.将[A,B]的值统一赋值为X
2.将[A,B]的值每一个都添加X的若干倍,方法为第一个+X,之后的+2X,3X,.....,kX,如此递推
3.在第C个数之前插入数值X
4.求区间[A,B]的和。
具体参考如下:
序列初始长度为N,开始给出这N个数,之后又M个操作,其中N,M<=100,000 ,A,B均合法,X<=100(其实在64位范围就行了),结果在64位整型内。
分析:
这道题是个典型的序列维护的问题,且维护为区间块,有插入操作,需要惰性维护。
splay和块状链表都可以完成这种维护操作。
以下splay解:
①:插入,求和自不必说。。
②:将[A,B]整体赋值的操作,显然在维护的节点上加入两个域即可满足要求。这里记为clear(int),clFlag(bool)标记该子树是否被赋值,如果被赋值则为true
将clear赋值为-INF的时候表示未赋值可以省去变量clFlag
③:整体加法操作:
考虑之前有[A,B]+X,其子树记为R
后来因为R的旋转等因素将[A,B]分割成[A,C] + [C+1,B],这种时候A到C还是每个元素从+X,+2X,...,+kX,而C+1到B的部分则变成了+(k+1)X,....,+(k+m)X了,
也就是+kX+X,....,+kX+mX
其中k为子树[A,C]的节点数,m为[C+1,B]的节点数。
故每个区间由2个域构成,一个是基础的X,一个是附加的kx,分别记为addition和st
④:操作的组合
考虑对区间值进行操作的赋值和整体加法共2种
其组合无非是4种:赋值&赋值,赋值&加法,加法&加法,加法&赋值。
在区间维护的时候(lazy操作),第二次赋值显然要覆盖第一次赋值,先加法后赋值之前的加法也被覆盖
第二次加法累加到第一次加法上即可,还有就是先赋值后加法。
故在维护的时候有四种情况:
1.该节点仅有赋值,则赋值操作。
2.该节点仅有加法,则加法操作。
3.该节点均有,则必然是先赋值后加法,如果是先加法后赋值,则在上次维护的时候加法被赋值覆盖掉,仅剩赋值操作了。
4.均无。
ps:注意lazy操作,update更新sum,size等域的时候,前提是子树的数据sum和size已经是正确的。
在维护函数help的时候,计算保证该节点的sum和size是正确的,由下往上update。
故凡是在向下搜索节点的时候都要help,在伸展操作的时候要update。
注意update的前提,旋转后要先维护在update。
附个代码:
#include <stdio.h> #include <ctype.h> const int maxn = 200010; const int INF = 0x7fffffff; int root , n , m , k ; typedef long long ll; int array[maxn] ; void help(int); struct node { int l,r,p; int size,clear; ll add,st,sum,key; void init() { l = p = r = add = st = sum = key = 0 ; clear = -INF ; size = 1 ; } } tree[maxn]; inline void update(int x) { if(!x) return ; tree[x].size = tree[tree[x].l].size+tree[tree[x].r].size+1; tree[x].sum = tree[tree[x].l].sum + tree[tree[x].r].sum + tree[x].key ; } inline int get() { int t = 0 ; bool flag = 0 ; char c; while(!isdigit(c = getchar())&&c!='-'); if(c=='-') flag = 1; else t = c - 48; while(isdigit(c = getchar())) t = (t << 1) + (t << 3) + c - 48; return flag?-t:t; } inline void rotate(int x,int type) { int y = tree[x].p; if(type) { tree[y].l = tree[x].r ; tree[x].r = y ; tree[tree[y].l].p = y ; } else { tree[y].r = tree[x].l ; tree[x].l = y ; tree[tree[y].r].p = y ; } tree[x].p = tree[y].p ; tree[y].p = x ; if( tree[tree[x].p].l == y ) tree[tree[x].p].l = x ; else tree[tree[x].p].r = x ; /*上次就是这个,这次还是!!!*/ help(tree[y].l); help(tree[y].r); update(y); update(x); } inline void splay(int x,int rr) //将x旋转到rr的儿子的位置 { if( x == rr ) return ; if( rr == 0 ) root = x ; while(tree[x].p!=rr) { int y = tree[x].p ; int z = tree[y].p ; if( z == rr ) rotate(x,tree[y].l==x); else { if( tree[z].l == y ) { if(tree[y].l==x) { rotate(y,1); rotate(x,1); } else { rotate(x,0); rotate(x,1); } } else { if(tree[y].r==x) { rotate(y,0); rotate(x,0); } else { rotate(x,1); rotate(x,0); } } } } } inline void help(int x) { if(!x) return ; if ( tree[x].clear != -INF ) { if( tree[x].add == 0 ) { tree[x].key = tree[x].clear ; tree[x].sum = (ll)tree[x].size * tree[x].clear ; tree[tree[x].r].clear = tree[tree[x].l].clear = tree[x].clear; tree[tree[x].r].add = tree[tree[x].l].add = 0 ; tree[tree[x].r].st = tree[tree[x].l].st = 0 ; } else { int xl = tree[x].l ; int xr = tree[x].r ; tree[x].key = (ll)tree[x].clear + (ll)( tree[xl].size + 1 )*tree[x].add + tree[x].st ; tree[x].sum = (ll)(tree[x].clear+tree[x].st)*tree[x].size+(ll)tree[x].size*(tree[x].size+1)/2*tree[x].add; tree[xl].clear = tree[xr].clear = tree[x].clear; tree[xl].add = tree[xr].add = tree[x].add ; tree[xl].st = tree[x].st ; tree[xr].st = tree[x].st + (ll)(tree[xl].size+1)*tree[xl].add; } } else { if( tree[x].add != 0 ) { int xl = tree[x].l ; int xr = tree[x].r ; tree[x].key += (ll)(tree[xl].size+1)*tree[x].add+tree[x].st ; tree[x].sum += (ll)tree[x].size * tree[x].st + (ll)tree[x].size * (tree[x].size+1) / 2 * tree[x].add ; tree[xl].add += tree[x].add ; tree[xl].st += tree[x].st ; tree[xr].add += tree[x].add ; tree[xr].st += (ll)(tree[xl].size+1)*tree[x].add + tree[x].st ; } } tree[x].st = tree[x].add = 0 ; tree[x].clear = -INF ; } void insert(int value,int pos); inline void build(int l,int r) { /*k = 3 ; tree[1].init(); tree[2].init(); tree[1].r = 2 ; tree[2].p = 1 ; update(1); root = 1 ; int i ; for( i = n ; i >= 1 ; i--) insert(array[i],1);*/ int temp = k ; //tree[k].init(); if( l == r ) { tree[k].sum = tree[k].key = array[l-1] ; tree[k].l = tree[k].r = 0 ; tree[k].clear = -INF; tree[k].add = tree[k].st = 0 ; tree[k].size = 1 ; } else { int mid = (l+r)>>1 , j = k ; tree[k].key = array[mid-1] ; if(mid==l) tree[k].l = 0 ; else { tree[j].l = ++k; tree[k].p = j ; build(l,mid-1); } tree[j].r = ++k; tree[k].p = j ; build(mid+1,r); tree[j].clear = -INF; tree[j].add = tree[j].st = 0 ; update(j); } } inline int Rank(int key) //查找第k个元素 { int cur = root , j = 0 ; while(1) { help(cur); if( 1+tree[tree[cur].l].size+j == key ) return cur ; else if( tree[tree[cur].l].size+j+1 < key ) { j += (tree[tree[cur].l].size+1) ; cur = tree[cur].r ; } else cur = tree[cur].l ; } } inline ll querySum(int l,int r) { int temp = Rank(l); int rr = Rank(r+2); splay(temp,0); splay(rr,temp); help(temp); help(rr); help(tree[rr].l); help(tree[tree[rr].l].l); help(tree[tree[rr].l].r); update(tree[rr].l); return tree[tree[rr].l].sum ; } //在pos前插入数据value inline void insert(int value,int pos) { int posTh = Rank(pos); splay(posTh,0); int temp = tree[posTh].r ; help(temp); while( tree[temp].l != 0 ) { temp = tree[temp].l ; help(temp); } tree[temp].l = ++k; int newnode = k ; tree[newnode].key = value ; tree[newnode].size = 1 ; tree[newnode].sum = value ; tree[newnode].l = tree[newnode].r = 0 ; tree[newnode].p = temp ; tree[newnode].clear = -INF; tree[newnode].add = tree[newnode].st = 0 ; splay(newnode,0); } void clear(int l,int r,int x) { int temp = Rank(l); int tmp = Rank(r+2); splay(temp,0); splay(tmp,temp); tree[tree[tmp].l].clear = x ; tree[tree[tmp].l].add = 0 ; } void addInterval(int l,int r,int x) { int temp = Rank(l); int tmp = Rank(r+2); splay(temp,0); splay(tmp,temp); int interval = tree[tmp].l ; tree[interval].add += x ; } inline void work() { int l , r , x , y , op ; while(m--) { op = get(); if( op == 1 ) { l = get(); r = get(); x = get(); clear(l,r,x); } else if( op == 4 ) { l = get(); r = get(); printf("%lld\n",querySum(l,r)); } else if( op == 3 ) { x = get(); y = get(); insert(y,x); } else { l = get(); r = get(); x = get(); addInterval(l,r,x); } } } inline void getArray(char str[],int value[],int st) //将字符串str中的数字写到value中去,自st开始,返回最后的num,无前导零 { int i , j , t , negative ; for( i = 0 , j = st ; str[i] ; i++) if((str[i]>=48&&str[i]<=57)||str[i]=='-') { if(str[i]=='-') negative = -1 , i++; else negative = 1 ; t = 0 ; while(str[i]>=48&&str[i]<=57) t = (t<<1)+(t<<3)+(str[i++]^48) ; value[j++] = t*negative ; } } char str[maxn*5] ; int main() { int i , j ; while( scanf("%d%d",&n,&m) == 2 ) { tree[0].init(); tree[0].size = 0 ; tree[1].p = 0 ; root = k = 1 ; getchar(); gets(str); getArray(str,array,1); build(1,n+2); work(); } return 0 ; }
相关文章推荐
- 【解题报告】 POJ 1182 食物链 并查集的经典应用+相对位置
- Pku acm 2492 A Bug's Life数据结构题目解题报告(十)---- 并查集的应用
- POJ1011 Sticks解题报告(经典搜索)
- 置换的基础应用(附POJ 3270 Cow Sorting 解题报告)
- POJ 1094 Sorting It All Out (拓扑排序) -- 解题报告
- 算法入门经典2 第5章解题报告
- (解题报告)入门经典2版———第三章习题1
- Leetcode 120. Triangle 三角形问题(动态规划经典) 解题报告
- [POJ 1000] A+B Problem 经典水题 C++解题报告 JAVA解题报告
- LeetCode - 268. Missing Number - stable_sort应用实例 - ( C++ ) - 解题报告
- 【排序专训】练习题 士兵站队(中位数应用) 解题报告
- IT规划的企业应用实践(4)研究背景 之 反视角看公开报告
- 各大IT公司2012校园招聘笔试面试整理--解题报告整理
- 2007年中国教育行业信息化建设与IT应用趋势研究报告
- Hdu 1754 I Hate It 线段树 解题报告
- POJ-1094 Sorting It All Out 解题报告
- 【解题报告】 HDU 1754 I Hate It 线段树 单点更新
- 训练题 极品飞车(并查集应用) 解题报告
- Codeforces Goodbye 2014 problem B ACM解题报告(经典的并查集)
- poj 1094 Sorting It All Out 解题报告