POJ 3468 伸展树建树

来源:互联网 发布:淘宝服装招商加盟代理 编辑:程序博客网 时间:2024/06/11 00:15

A Simple Problem with Integers
Time Limit: 5000MS Memory Limit: 131072KTotal Submissions: 59628 Accepted: 18180Case Time Limit: 2000MS

Description

You have N integers, A1A2, ... , AN. You need to deal with two kinds of operations. One type of operation is to add some given number to each number in a given interval. The other is to ask for the sum of numbers in a given interval.

Input

The first line contains two numbers N and Q. 1 ≤ N,Q ≤ 100000.
The second line contains N numbers, the initial values of A1A2, ... , AN. -1000000000 ≤ Ai ≤ 1000000000.
Each of the next Q lines represents an operation.
"C a b c" means adding c to each of AaAa+1, ... , Ab. -10000 ≤ c ≤ 10000.
"Q a b" means querying the sum of AaAa+1, ... , Ab.

Output

You need to answer all Q commands in order. One answer in a line.

Sample Input

10 51 2 3 4 5 6 7 8 9 10Q 4 4Q 1 10Q 2 4C 3 6 3Q 2 4

Sample Output

455915

Hint

The sums may exceed the range of 32-bit integers.

这题用线段树做得更快,代码也更少,不过为了学伸展树,所以搞了好久。

每个节点存储的信息:

int pre[maxn];     当前节点的前驱

int ch[maxn][2];当前节点的左右子树

int val[maxn];当前节点的值

int size[maxn];当前节点的子树的节点个数

int lazy[maxn];当前节点的子树被增加的值

LL sum[maxn];当前节点的子树的总值

当Q X Y的时候,就把x-1节点设置成根节点。y+1节点设置成根节点的右子树。

那么sum[ch[ch[root][1]][0]]即为结果。

当C X Y k的时候,就把x-1节点设置成根节点。y+1节点设置成根节点的右子树。

然后lazy[ch[ch[root][1]][0]]+=k;

因为把x-1设置成根节点,y+1设成根节点的右子树后,右子树的左子树就包含x到y区间的数了。

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<map>#include<queue>#include<set>#include<cmath>#include<bitset>#define mem(a,b) memset(a,b,sizeof(a))#define INF 1000000#define maxn 100010using namespace std;typedef long long ll;typedef unsigned long long ull;struct splaytree //伸展树{    int pre[maxn];//前驱    int key[maxn];//键值    int ch[maxn][2];//左右孩子    int a[maxn];//数列    int size[maxn];//这颗树下面有多少个结点    int lazy[maxn];    ll sum[maxn];    int root,tot,n;//根节点,节点数量    void create()    {        tot=root=0;        mem(ch,0);  mem(size,0);        mem(pre,0);  mem(lazy,0);        mem(key,0);  mem(sum,0);    }    void dfs(int x)    {        if(x)        {            dfs(ch[x][0]);            printf("结点:%2d   左儿子:%2d   右儿子:%2d   父结点:%2d   值为:%2d   节点数:%2d\n",x,ch[x][0],ch[x][1],pre[x],key[x],size[x]);            dfs(ch[x][1]);        }    }    void debug()    {        printf("根结点为:%d\n",root);        dfs(root);    }    void newnode(int &r,int father,int k)    {//在r位置,父亲为father,新建一个值点。        r=++tot;        pre[r]=father;        key[r]=k;        sum[r]=k;        lazy[r]=0;        size[r]=1;        ch[r][0]=ch[r][1]=0;    }    void push_down(int x)    {        key[x]+=lazy[x];        lazy[ch[x][1]]+=lazy[x];        lazy[ch[x][0]]+=lazy[x];        sum[ch[x][1]]+=(ll)lazy[x]*size[ch[x][1]];        sum[ch[x][0]]+=(ll)lazy[x]*size[ch[x][0]];        lazy[x]=0;    }    void push_up(int x)    {        size[x]=size[ch[x][1]]+size[ch[x][0]]+1;        sum[x]=sum[ch[x][1]]+sum[ch[x][0]]+lazy[x]+key[x];    }    void rotate(int x,int kind)//kind=1表示右旋,kind=0表示左旋    {        int y=pre[x];        push_down(x);push_down(y);        ch[y][!kind]=ch[x][kind];        pre[ch[x][kind]]=y;        ch[x][kind]=y;        if(pre[y]) ch[pre[y]][ch[pre[y]][1]==y]=x;        pre[x]=pre[y];        pre[y]=x;        push_up(y);    }    void splay(int x,int goal) //goal=0则把x伸展到根,否则伸展到根的右子树    {        push_down(x);        while(pre[x]!=goal)        {            if(pre[pre[x]]==goal) rotate(x,ch[pre[x]][0]==x);            else            {                int y=pre[x];                int kind=ch[pre[y]][0]==y;                if(ch[y][kind]==x) rotate(x,!kind),rotate(x,kind);                else rotate(y,kind),rotate(x,kind);            }        }        push_up(x);        if(!goal) root=x;//把root更新成x    }    int find(int rank)//查找对应排名的结点编号    {        int r=root;        push_down(r);        while(size[ch[r][0]]!=rank)        {            if(rank<size[ch[r][0]]) r=ch[r][0];            else            {                rank-=size[ch[r][0]]+1;                r=ch[r][1];            }            push_down(r);        }        return r;    }    int insert(int x)//插入值x    {        int r=root;        while(ch[r][key[r]<x])        {            if(key[r]==x) {splay(r,0);return 0;}            r=ch[r][key[r]<x];        }        newnode(ch[r][x>key[r]],r,x);        splay(ch[r][x>key[r]],0);        return 1;    }    int get_pre(int x)//寻找节点x的前驱的值,未找到则返回INF    {        int r=ch[x][0];        if(!r) return -INF;        while(ch[r][1]) r=ch[r][1];        return key[r];    }    int get_next(int x)    {        int r=ch[x][1];        if(!r) return INF;        while(ch[r][0]) r=ch[r][0];        return key[r];    }    void update(int l,int r,int k)    {        splay(find(l-1),0);        splay(find(r+1),root);        lazy[ch[ch[root][1]][0]]+=k;        sum[ch[ch[root][1]][0]]+=(ll)size[ch[ch[root][1]][0]]*k;    }    ll query(int l,int r)    {        splay(find(l-1),0);        splay(find(r+1),root);        return sum[ch[ch[root][1]][0]];    }    void build(int &x,int l,int r,int father)    {        if(l>r) return ;        int mid=(l+r)/2;        newnode(x,father,a[mid]);        if(l<mid) build(ch[x][0],l,mid-1,x);        if(r>mid) build(ch[x][1],mid+1,r,x);        push_up(x);    }    void start()    {        newnode(root,0,-INF);        newnode(ch[root][1],root,-INF);        size[root]=2;        build(ch[ch[root][1]][0],1,n,ch[root][1]);        //在父结点值为-1的左子树建树不符合排序二叉树,这个有点不理解        push_up(ch[root][1]);        push_up(root);    }}tree;int main(){    int n,q,i;    while(~scanf("%d%d",&n,&q))    {        tree.create();        tree.n=n;        for(i=1;i<=n;i++)            scanf("%d",&tree.a[i]);        tree.start();        //tree.debug();        while(q--)        {            char str[4];            int x,y,k;            scanf("%s%d%d",str,&x,&y);            if(str[0]=='Q')                printf("%lld\n",tree.query(x,y));            else            {                scanf("%d",&k);                tree.update(x,y,k);            }        }    }    return 0;}


0 0
原创粉丝点击