soj 4018upit解题报告 splay经典应用
来源:互联网 发布:java搭建项目的流程 编辑:程序博客网 时间:2024/05/24 22:43
时隔一年,终于解决了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。
附个代码:
#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前插入数据valueinline 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 ;}
- soj 4018upit解题报告 splay经典应用
- SOJ Dollars 解题报告
- SOJ 连分数问题解题报告
- 3188: [Coci 2011]Upit splay
- bzoj 3223 splay 解题报告
- BZOJ 3223 Splay 解题报告
- BZOJ 1269 [AHOI 2006] STL(rope)\SPLAY 解题报告
- 【解题报告】 POJ 1182 食物链 并查集的经典应用+相对位置
- POJ1011 Sticks解题报告(经典搜索)
- zoj 1013解题报告 经典DP
- 经典dp poj2626 chess解题报告
- pku1734 Floyd_Warshal算法应用 解题报告
- hdu1106排序解题报告 STL的应用
- 反正切函数的应用解题报告
- [bzoj3188]Upit
- 杭电OJ1466动态规划经典题(解题报告)
- poj 2689解题报告(区间筛素数,经典)
- soj4059 Towns along a Highway解题报告 经典dfs
- 8月25日
- 《C专家编程》看到的一种有意思的画图方法
- 电容的用法:去耦、旁路、滤波等
- 史记·商君列传
- Android 通过Android SDK Manager 安装英特尔® 凌动™ Android* x86 模拟器映像插件
- soj 4018upit解题报告 splay经典应用
- [Activeden] Flexible Flash Template flash网站模版源码
- iPhone开发之UITableView入门2
- g++链接lib库时的顺序
- 如何安装appsync
- Android 八款开源 Android 游戏引擎 (巨好的资源)
- HDU 3339 In Action 解题报告(最短路+背包)
- HDU 4393 Throw nails
- 开始学习WEB技术