A Simple Problem with Integers+poj+splay树区间操作

A Simple Problem with Integers
Time Limit: 5000MS Memory Limit: 131072K
Total Submissions: 66557 Accepted: 20467
Case 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 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
 
解决方案:此题重点考察的是splay树的区间操作,和线段树有点相似,在节点上加一个add,sum,v标志,当进行旋转,伸展操作时,注意对标志的下移和节点的向上更新。而且建立一个splay树的时候,要直接把区间放在root->ch[1]->ch[0]上,然后通过伸展操作把要查询或更新的区间旋转到root->ch[1]->ch[0]。
code:
<pre name="code" class="cpp">#include <iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
struct node
{
    node *ch[2];
    int s;
    int v;
    long long  sum;
    int add;
    int cmp(int k)const
    {
        int d=k-ch[0]->s;
        if(d==1) return -1;
        return d<=0?0:1;
    }
    void maintain()
    {
        s=ch[0]->s+ch[1]->s+1;
        sum=v+ch[0]->sum+ch[1]->sum;
    }
    void updatedown(int c)
    {
        v+=c,add+=c,sum+=1LL*s*c;
    }
    void pushdown()
    {
        if(add)
        {
            ch[0]->updatedown(add);
            ch[1]->updatedown(add);
            add=0;
        }
    }

};
node *null=new node();
void rotate(node *&o,int d)
{

    node *k=o->ch[d^1];
    o->ch[d^1]=k->ch[d];
    k->ch[d]=o;
    o->maintain();
    k->maintain();
    o=k;
}
void splay(node *&o,int k)
{
    o->pushdown();
    int d=o->cmp(k);
    if(d==1) k-=(o->ch[0]->s+1);
    if(d!=-1)
    {
        node *p=o->ch[d];
        p->pushdown();
        int d2=p->cmp(k);
        int k2=(d2==0?k:k-p->ch[0]->s-1);
        if(d2!=-1)
        {
            splay(p->ch[d2],k2);
            if(d==d2) rotate(o,d^1);
            else rotate(o->ch[d],d);
        }
        rotate(o,d^1);
    }
}
const int maxn=100000+10;
int input[maxn];
struct splaysequence
{
    int n,index;
    node seq[maxn];
    node *root;
    node *build(int sz)
    {
        if(!sz) return null;
        node *L=build(sz/2);
        node *o=&seq[++n];
        o->v=o->sum=input[index++];
        o->ch[0]=L;
        o->ch[1]=build(sz-sz/2-1);
        o->s=o->add=0;
        o->maintain();
        return o;
    }
    void init(int sz)
    {
        index=1;
        null->add=null->s=null->sum=null->v=0;
        root=&seq[0];
        root->ch[0]=null,root->ch[1]=null;
        root->add=root->s=root->sum=root->v=0;
        root->ch[1]=&seq[1];
        root->ch[1]->ch[0]=null,root->ch[1]->ch[1]=null;
        root->ch[1]->add=root->ch[1]->s=root->ch[1]->sum=root->ch[1]->v=0;
        n=1;
        root->ch[1]->maintain();
        root->maintain();
        root->ch[1]->ch[0]=build(sz);
    }


};
void update(node *&root)
{
    int l,r,c;
    scanf("%d%d%d",&l,&r,&c);
    splay(root,l);
    splay(root->ch[1],r-l+2);
    root->ch[1]->ch[0]->updatedown(c);
}
void query(node *&root)
{
    int l,r;
    scanf("%d%d",&l,&r);
    splay(root,l);
    splay(root->ch[1],r-l+2);
    printf("%lld\n",root->ch[1]->ch[0]->sum);
}
splaysequence ss;
int main()
{
    int n,m;
    while(~scanf("%d%d",&n,&m))
    {
        for(int i=1; i<=n; i++)
        {
            scanf("%d",&input[i]);
        }
        input[0]=-1;
        input[n+2]=-1;
        ss.init(n);
        for(int i=1; i<=m; i++)
        {
            char op[4];
            scanf("%s",op);
            if(op[0]=='Q')
            {
                query(ss.root);
            }
            else
            {
                update(ss.root);
            }
        }

    }
    return 0;
}



                
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值