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

你可能感兴趣的:(Integer)