Poj3468-A Simple Problem with Integers(伸展树练练手)

Description

You have N integers, A1, A2, ... , 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 A1, A2, ... , AN. -1000000000 ≤ Ai ≤ 1000000000. Each of the next Q lines represents an operation. "C a b c" means adding c to each of Aa, Aa+1, ... , Ab. -10000 ≤ c ≤ 10000. "Q a b" means querying the sum of Aa, Aa+1, ... , Ab.

Output

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

Sample Input

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

Sample Output

4
55
9
15

题意: 给出N个数,有两种操作
Q a b 查询[a,b]区间的和
C a b c [a,b]区间所有值加上c

解析:成段更新问题,线段树已经可以做,我试着用伸展树做做。

代码:
//这题用线段树就可以做了,拿来用伸展树练练手
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
using namespace std;
typedef long long LL;
const int maxn=100005;
int A[maxn],cnt;  //A数组保存数,cnt是节点标号,我是用数组模拟的
struct treap
{
    treap* son[2];  //左右儿子
    int s;
    LL v,add,sum;
    treap(){  s=v=add=sum=0; son[0]=son[1]=NULL; }
    treap(LL nv);
    int rk(){ return son[0]->s+1; }  //排名,第几个数
    int cmp(int k)  //比较,如果相等返回-1,小于返回0,大于1
    {
        if(k==rk()) return -1;
        return k<rk()?0:1;
    }
    void Set(LL d)
    {
        v+=d;
        add+=d;
        sum+=d*s;
    }
    void pushup()
    {
        s=son[0]->s+son[1]->s+1;
        sum=son[0]->sum+son[1]->sum+v;
    }
    void pushdown()  //处理懒惰标记
    {
        if(add!=0)
        {
            son[0]->Set(add);
            son[1]->Set(add);
            add=0;
        }
    }
}null,tr[maxn];
treap::treap(LL nv)
{
    sum=v=nv;
    s=1;
    add=0;
    son[0]=son[1]=&null;
}
treap* NewNode(LL x)
{
    tr[cnt]=treap(x);
    return tr+cnt++;
}
struct splaytree
{
    int Size;
    treap* root;
    splaytree(){ Size=0; root=&null; }
    void Rotate(treap* &t,int d)  //翻转操作
    {
        t->pushdown();
        treap* p=t->son[d^1];
        p->pushdown();
        t->son[d^1]=p->son[d];
        p->son[d]=t;
        t->pushup();
        t=p;
        t->pushup();
    }
    void Splay(treap* &t,int k)  //将第k大的节点伸展到根
    {
        t->pushdown();
        int d=t->cmp(k);
        if(d!=-1)
        {
            if(d) Splay(t->son[d],k- t->rk());
            else Splay(t->son[d],k);
            Rotate(t,d^1);
        }
    }
    void Build(treap* &t,int le,int ri)  //将N个数建成一棵树
    {
        if(le>ri) return;
        int mid=(le+ri)/2;
        t=NewNode(A[mid]);
        Build(t->son[0],le,mid-1);
        Build(t->son[1],mid+1,ri);
        t->pushup();
    }
    LL Query(treap* &t,int x,int y)
    {
        LL ret=0;
        Splay(t,y);
        ret+=t->son[0]->sum+t->v;
        if(x>1)
        {
            Splay(t,x-1);
            ret-=t->son[0]->sum+t->v;
        }
        return ret;
    }
    void Add(treap* &t,int x,int y,int add)
    {
        Splay(t,y);
        t->v+=add; t->sum+=add*y;
        t->son[0]->Set(add);
        if(x>1)
        {
            Splay(t,x-1);
            t->v-=add; t->sum-=add*(x-1);
            t->son[0]->Set(-add);
        }
    }
};
int main()
{
    int N,Q;
    while(scanf("%d%d",&N,&Q)!=EOF)
    {
        for(int i=1;i<=N;i++) scanf("%d",&A[i]);
        splaytree spt;
        cnt=0;
        spt.Build(spt.root,1,N);
        int x,y,d;
        char op[3];
        while(Q--)
        {
            scanf("%s",op);
            if(op[0]=='Q')
            {
                scanf("%d%d",&x,&y);
                printf("%lld\n",spt.Query(spt.root,x,y));
            }
            else
            {
                scanf("%d%d%d",&x,&y,&d);
                spt.Add(spt.root,x,y,d);
            }
        }
    }
    return 0;
}
View Code

 

posted @ 2016-08-03 15:18  wust_ouyangli  阅读(132)  评论(0编辑  收藏  举报