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
posted @ 2013-04-17 12:59  yefeng1627  阅读(193)  评论(0编辑  收藏  举报

Launch CodeCogs Equation Editor