poj 3468 A Simple Problem with Integers 区间更新与询问 Splay简单应用
Splay 的属性
1 struct Splay{ 2 int rt, cnt; 3 int ch[N][2], pre[N], sz[N]; 4 LL sum[N], add[N], val[N]; 5 }
Splay 的操作主要集中在
1. Rotate( x, d ) 旋转分为 左旋(d=0), 右旋(d=1)
2. Splay( x, goal ) 将节点x 旋转到 节点goal下
3. Rotate_To( k, goal ) 将左数第k个节点旋转到 节点goal 下
1 void rotate(int x,int d){ 2 int y = pre[x]; 3 push_down(y); push_down(x); 4 ch[y][d^1] = ch[x][d]; 5 pre[ ch[x][d] ] = y; 6 pre[x] = pre[y]; 7 if( pre[y] ) ch[ pre[y] ][ ch[pre[y]][1] == y ] = x; 8 ch[x][d] = y; 9 pre[y] = x; 10 push_up(y); //push_up(x); 11 }
1 void splay(int x,int goal){ 2 // satisfy the x under the goal; 3 push_down(x); 4 while( pre[x] != goal ){ 5 int y = pre[x]; 6 if( pre[y] == goal ) rotate( x, ch[y][0] == x ); 7 else{ 8 int z = pre[y]; 9 int d1 = ch[z][0]==y, d2 = ch[y][0]==x; 10 if( d1 == d2 ) rotate( y, d1 ), rotate( x, d2 ); 11 else rotate( x, d2 ), rotate( x, d1 ); 12 } 13 } 14 push_up(x); 15 if(goal == 0) rt = x; 16 }
1 void rotate_to(int k, int goal){ 2 // find the x of it's left-child size is k 3 // because of we add two virtual point 4 int x = rt; 5 while( sz[ ch[x][0] ] != k ){ 6 if( sz[ ch[x][0] ] > k ) x = ch[x][0]; 7 else k -= (sz[ ch[x][0] ]+1), x = ch[x][1]; 8 push_down(x); 9 } 10 // printf("x is %d\n", x); 11 splay(x,goal); 12 }
完整解题代码:
View Code
#include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> using namespace std; #define keytree ch[ ch[rt][1] ][0] const int N = 1e5+10; typedef long long LL; int tmp[N]; struct Splay{ int rt, cnt; int ch[N][2], pre[N], sz[N]; LL sum[N], add[N], val[N]; //Splay Operator void rotate(int x,int d){ int y = pre[x]; push_down(y); push_down(x); ch[y][d^1] = ch[x][d]; pre[ ch[x][d] ] = y; pre[x] = pre[y]; if( pre[y] ) ch[ pre[y] ][ ch[pre[y]][1] == y ] = x; ch[x][d] = y; pre[y] = x; push_up(y); //push_up(x); } void splay(int x,int goal){ // satisfy the x under the goal; push_down(x); while( pre[x] != goal ){ int y = pre[x]; if( pre[y] == goal ) rotate( x, ch[y][0] == x ); else{ int z = pre[y]; int d1 = ch[z][0]==y, d2 = ch[y][0]==x; if( d1 == d2 ) rotate( y, d1 ), rotate( x, d2 ); else rotate( x, d2 ), rotate( x, d1 ); } } push_up(x); if(goal == 0) rt = x; } void rotate_to(int k, int goal){ // find the x of it's left-child size is k // because of we add two virtual point int x = rt; while( sz[ ch[x][0] ] != k ){ if( sz[ ch[x][0] ] > k ) x = ch[x][0]; else k -= (sz[ ch[x][0] ]+1), x = ch[x][1]; push_down(x); } // printf("x is %d\n", x); splay(x,goal); } //Tree Operator void NewNode(int &x,int c){ x = ++cnt; ch[x][0]=ch[x][1]=pre[x]=0; sum[x]=val[x]=c; add[x] = 0; sz[x] = 0; } void push_up(int x){ if( x == 0 ) return; sum[x] = val[x] + sum[ch[x][0]] + sum[ch[x][1]]; sz[x] = 1 + sz[ch[x][0]] + sz[ch[x][1]]; } void push_down(int x){ if( add[x] ){ val[x] += add[x]; add[ch[x][0]] += add[x]; add[ch[x][1]] += add[x]; sum[ch[x][0]] += 1LL*sz[ch[x][0]]*add[x]; sum[ch[x][1]] += 1LL*sz[ch[x][1]]*add[x]; add[x] = 0; } } void build(int &x, int l,int r,int f){ if( l > r ) return; int m = (l+r)>>1; NewNode( x, tmp[m] ); pre[x] = f; build( ch[x][0], l, m-1, x ); build( ch[x][1], m+1, r, x ); push_up( x ); } void update(int l,int r,int c){ rotate_to( l-1, 0 ); rotate_to( r+1, rt ); add[keytree] += c; sum[keytree] += 1LL*sz[keytree]*c; } LL query(int l,int r){ rotate_to( l-1, 0 ); rotate_to( r+1, rt); return sum[keytree]; } void init(int n){ rt = cnt = 0; ch[0][0]=ch[0][1]=pre[0]=sz[0]=val[0]=sum[0]=add[0]=0; //init the Null Node; NewNode( rt, 0); NewNode( ch[rt][1], 0 ); pre[ ch[rt][1] ] = rt; build( keytree, 0, n-1, ch[rt][1] ); push_up( ch[rt][1] ), push_up( rt ); // print(rt); } void print(int x){ if(x==0) printf("Tree is NULL!\n"); if( ch[x][0] ) print(ch[x][0]); printf("cur:%d lch:%d rch:%d sum:%lld sz:%d val:%lld\n", x,ch[x][0],ch[x][1],sum[x],sz[x],val[x]); if( ch[x][1] ) print(ch[x][1]); } }spt; int main(){ int n, m; while( scanf("%d%d",&n,&m) != EOF){ for(int i = 0; i < n; i++) scanf("%d", &tmp[i] ); spt.init(n); char op[5]; int a, b, c; for(int i = 0; i < m; i++){ scanf("%s", op ); if( op[0] == 'C' ){ scanf("%d%d%d",&a,&b,&c); spt.update( a, b, c ); } else{ scanf("%d%d",&a,&b); printf("%lld\n", spt.query(a,b) ); } } } return 0; }
11486939 | yefeng1627 | 3468 | Accepted | 4488K | 3766MS | C++ | 3275B | 2013-04-17 12:14:30 |
线段树代码:
View Code
#include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> using namespace std; #define lch rt<<1,l,m #define rch rt<<1|1,m+1,r const int N = 111111; typedef long long LL; LL sum[N<<2], add[N<<2]; int n; void push_up(int rt){ sum[rt] = sum[rt<<1] + sum[rt<<1|1]; } void push_down(int rt,int len){ if( add[rt] ){ add[rt<<1] += add[rt]; add[rt<<1|1] += add[rt]; sum[rt<<1] += 1LL*(len-(len>>1))*add[rt]; sum[rt<<1|1] += 1LL*(len>>1)*add[rt]; add[rt] = 0; } } void build(int rt,int l,int r){ sum[rt] = add[rt] = 0; if( l == r ){ scanf("%lld", &sum[rt] ); return; } int m = (l+r)>>1; build(lch), build(rch); push_up(rt); } void update(int rt,int l,int r,int a,int b,int c){ if( a <= l && r <= b ){ sum[rt] += 1LL*(r-l+1)*c; add[rt] += c; return; } push_down(rt,r-l+1); int m = (l+r)>>1; if( a <= m ) update(lch,a,b,c); if( m < b ) update(rch,a,b,c); push_up(rt); // After update ,should push_up to parent. } LL query(int rt,int l,int r,int a,int b){ if( a <= l && r <= b ) return sum[rt]; push_down(rt,r-l+1); int m = (l+r)>>1; LL res = 0; if( a <= m ) res += query(lch,a,b); if( m < b ) res += query(rch,a,b); return res; } int main(){ int m; while( scanf("%d%d", &n,&m) != EOF){ build( 1, 1, n ); char op[5]; int a, b, c; for(int i = 0; i < m; i++){ scanf("%s", op ); if( op[0] == 'C' ){ scanf("%d%d%d",&a,&b,&c); update(1,1,n,a,b,c); } else{ scanf("%d%d", &a,&b); printf("%lld\n", query(1,1,n,a,b) ); } } } return 0; }
11487052 | yefeng1627 | 3468 | Accepted | 4520K | 2641MS | G++ | 1559B | 2013-04-17 12:41:41 |