3188: [Coci 2011]Upit splay

来源:互联网 发布:网络信息安全培训记录 编辑:程序博客网 时间:2024/06/10 01:39

splay,对于区间加等差数列的操作,我们可以发现等差数列的首项和公差是可以分开考虑并且可叠加的。那么就打标记就好了。

#include<iostream>#include<cstdio>using namespace std;const int N=200005;int n,Q,t1,t2,tot,root;int fa[N],tree[N][2];long long size[N],sum[N],tag[N][4],val[N];inline long long read(){    long long a=0,f=1; char c=getchar();    while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();}    while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();}    return a*f;}inline void modify(int k,long long x){    tag[k][0]=1; tag[k][1]=x;     tag[k][2]=0; tag[k][3]=0;    sum[k]=size[k]*x; val[k]=x;}inline void update(int k,long long y,long long z){    tag[k][2]+=y; tag[k][3]+=z;    val[k]+=y+size[tree[k][0]]*z;    sum[k]+=size[k]*y+size[k]*(size[k]-1)/2ll*z;}inline void pushup(int k){    sum[k]=sum[tree[k][0]]+sum[tree[k][1]]+val[k];    size[k]=size[tree[k][0]]+size[tree[k][1]]+1;}inline void pushdown(int k){    if (tag[k][0])    {        modify(tree[k][0],tag[k][1]);        modify(tree[k][1],tag[k][1]);        tag[k][0]=0;    }    if (tag[k][2]||tag[k][3])    {        update(tree[k][0],tag[k][2],tag[k][3]);        update(tree[k][1],tag[k][2]+tag[k][3]*(size[tree[k][0]]+1),tag[k][3]);        tag[k][2]=tag[k][3]=0;    }}inline void rotate(int x,int &k){    int y=fa[x],z=fa[y],l=tree[y][1]==x,r=l^1;    if (y==k) k=x; else tree[z][tree[z][1]==y]=x;    fa[x]=z; fa[y]=x; fa[tree[x][r]]=y;    tree[y][l]=tree[x][r]; tree[x][r]=y;    pushup(y); pushup(x);}inline void splay(int x,int &k){    while (x!=k)    {               int y=fa[x],z=fa[y];        if (y!=k)        {            if (tree[y][0]==x^tree[z][0]==y) rotate(x,k); else rotate(y,k);        }        rotate(x,k);    }}int find(int k,int x){    pushdown(k);    if (size[tree[k][0]]+1==x) return k;    else if (size[tree[k][0]]+1>x) return find(tree[k][0],x);    else return find(tree[k][1],x-size[tree[k][0]]-1);}inline void split(int x,int y){    t1=find(root,x); t2=find(root,y);    splay(t1,root); splay(t2,tree[t1][1]);}void build(int l,int r,int f){    if (l>r) return;    int mid=l+r>>1;    fa[mid]=f; tree[f][mid>f]=mid;    if (l==r) {sum[mid]=val[mid]; size[mid]=1; return;}    build(l,mid-1,mid); build(mid+1,r,mid);    pushup(mid);}int main(){//  freopen("txt.in","r",stdin);//  freopen("my.out","w",stdout);    n=read(); Q=read();    for (int i=2;i<=n+1;i++) val[i]=read();    root=(n+3)>>1; tot=n+2;    build(1,n+2,0);    while (Q--)    {        int opt=read();        long long z;        if (opt==3)        {            int x=read();            split(x,x+1);            tree[t2][0]=++tot;            fa[tot]=t2;            val[tot]=sum[tot]=read();            size[tot]=1;        }        else        {            int x=read(),y=read();            split(x,y+2);            if (opt==1) modify(tree[t2][0],read());            else if (opt==4) printf("%lld\n",sum[tree[t2][0]]);            else z=read(),update(tree[t2][0],z,z);        }        pushup(t2); pushup(t1);    }    return 0;}
0 0