poj 3468 A Simple Problem with Integers(splay tree更新求和)

题目地址:http://poj.org/problem?id=3468

区间更新,加上某值,区间求和,用splay  tree做,可以当模版了。。。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
#define N 200010
#define Key_value ch[ch[root][1]][0]
using namespace std;
int key[N],n;
int pre[N];
int ch[N][2],tot,root,node[N];
ll add[N],size[N];ll sum[N];int data[N];
void newnode(int &r,int k,int fa)
{
  r=++tot;
  ch[r][0]=ch[r][1]=0;
  pre[r]=fa;
  key[r]=sum[r]=k;
  add[r]=0;
  size[r]=1;
}
void push_up(int r)
{
    size[r]=size[ch[r][0]]+size[ch[r][1]]+1;
    sum[r]=add[r]+key[r]+sum[ch[r][0]]+sum[ch[r][1]];
}
void push_down(int r)
{
    if(add[r])
    {
        key[r]+=add[r];
        add[ch[r][0]]+=add[r];
        add[ch[r][1]]+=add[r];
        sum[ch[r][0]]+=(ll)size[ch[r][0]]*add[r];
        sum[ch[r][1]]+=(ll)size[ch[r][1]]*add[r];
        add[r]=0;
    }
}
void build(int &r,int L,int R,int fa)
{
    if(L>R)
    return;
    int mid=(L+R)/2;
    newnode(r,data[mid],fa);
    build(ch[r][0],L,mid-1,r);
    build(ch[r][1],mid+1,R,r);
    push_up(r);
}
void Init()
{
    tot=root=0;
    ch[0][0]=ch[0][1]=pre[0]=size[0]=sum[0]=add[0]=0;
    newnode(root,-1,0);
    newnode(ch[root][1],-1,root);
    //size[root]=2;
    for(int i=0;i<n;i++)
    scanf("%d",&data[i]);
    build(Key_value,0,n-1,ch[root][1]);
    push_up(ch[root][1]);
    push_up(root);
}
void Rotate(int x,int kind)
{
    int y=pre[x];
    push_down(y);
    push_down(x);
    ch[y][!kind]=ch[x][kind];
    pre[ch[x][kind]]=y;
    if(pre[y])
    ch[pre[y]][ch[pre[y]][1]==y]=x;
    pre[x]=pre[y];
    ch[x][kind]=y;
    pre[y]=x;
    push_up(y);
}
void splay(int r,int goal)
{
    push_down(r);
    while(pre[r]!=goal)
    {
        if(pre[pre[r]]==goal)
        Rotate(r,ch[pre[r]][0]==r);
        else
        {
            int y=pre[r];
            int kind=(ch[pre[y]][0]==y);
            if(ch[y][kind]==r)
            {
                Rotate(r,!kind);
                Rotate(r,kind);
            }
            else
            {
                Rotate(y,kind);
                Rotate(r,kind);
            }
        }
    }
    push_up(r);
    if(goal==0)
    root=r;
}
void RotateTo(int k,int goal)
{
    int r=root;
    push_down(r);
    while(size[ch[r][0]]!=k)
    {
        if(k<size[ch[r][0]])
        r=ch[r][0];
        else
        {
            k-=(size[ch[r][0]]+1);
            r=ch[r][1];
        }
        push_down(r);
    }
    splay(r,goal);
}
void update(int l,int r,int c)
{
   RotateTo(l-1,0);
   RotateTo(r+1,root);
   add[Key_value]+=c;
   sum[Key_value]+=(ll)c*size[Key_value];
}
void query(int l,int r)
{
    RotateTo(l-1,0);
   RotateTo(r+1,root);
   printf("%lld\n",sum[Key_value]);
}
char str[3];
int main() {
	int  m,l,r,c;
	scanf("%d%d",&n,&m);
	Init();
	while(m --) {
		char op[2];
		scanf("%s",op);
		if(op[0] == 'Q') {
		    scanf("%d%d",&l,&r);
			query(l,r);
		} else {
		    scanf("%d%d%d",&l,&r,&c);
			update(l,r,c);
		}
	}
	return 0;
}


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值