【例题】【Splay】NKOJ2504 区间翻转问题

来源:互联网 发布:大疆无人机 知乎 编辑:程序博客网 时间:2024/03/29 21:12

NKOJ2504 区间翻转问题
时间限制 : 10000 MS 空间限制 : 265000 KB

问题描述
给你一个长度为N的序列{ai}和M个操作
1.查询第k个数的值
2.将第k个数增加d
3.查询一段区间的和
4.查询一段区间的最大值
5.将一段区间镜面翻转(例如序列{1,2,3,4,5,6},将从2到5的区间翻转后得到序列{1,5,4,3,2,6})
对于除操作2,5以外的操作,输出相应的答案

输入格式
第一行两个正整数N,M
第二行N个整数,为初始的序列
第三行到底M+2行,每行若干个整数
·如果第一个数为1,那么后面一个正整数k,表示查询第k个数的值
·如果第一个数是2,那么后面两个正整数k,d,表示将ak增加d
·如果第一个数为3,那么后面两个正整数l,r,表示查询从al到ar的区间和
·如果第一个数为4,那么后面两个正整数l,r,表示查询从al到ar的最大值
·如果第一个数为5,那么后面两个正整数l,r,表示翻转从al到ar的这个区间

输出格式
除操作2,5外每个操作输出占一行,一个整数,为本次提问的答案

样例输入
6 8
1 2 3 4 5 6
1 4
3 2 5
4 2 2
5 2 5
3 1 3
5 2 5
2 5 1
4 1 6

样例输出
4
14
2
10
6

提示
2<=N<=100000
1<=M<=100000
原序列1<=ai<=1000
每次1<=k<=N,1<=l<=r<=N,1<=d<=1000

来源 感谢nodgd命题并提供数据

思路:
维护下标,将每个数的下标存入树中。
(1)、查询第k个数:直接找
(2)、第k个数增加d:直接加
(3)、维护区间和。操作时将x-1为根、y+1为右儿子,则y+1左儿子的sum即为所求
(4)、维护区间最大。操作同(3)
(5)、lazy标记。操作同(3),再将y+1左儿子打标记

(3)、(4)、(5)注意覆盖1或n的情况特殊处理

#include<cstdio>#include<iostream>using namespace std;const int need=100005;int a[need];//.............................................inline void in_(int &d){    char t=getchar();bool mark=0;    while(t<'0'||t>'9') {if(t=='-') mark=1;t=getchar();}    for(d=0;!(t<'0'||t>'9');t=getchar()) d=(d<<1)+(d<<3)+t-'0';if(mark) d=-d;}inline void out_(int x){    if(x<0) {x=-x;putchar('-');}    if(x>=10) out_(x/10);    putchar(x%10+'0');}//.............................................int tot,root;int fa[need],ls[need],rs[need],si[need],num[need],sum[need],mm[need];bool lazy[need];inline void putdown(int x){    lazy[x]=0;    swap(ls[x],rs[x]);    if(ls[x]) lazy[ls[x]]^=1;    if(rs[x]) lazy[rs[x]]^=1;} inline void NBHB(int x){    si[x]=si[ls[x]]+si[rs[x]]+1;    sum[x]=sum[ls[x]]+sum[rs[x]]+a[num[x]];    mm[x]=max(a[num[x]],max(mm[ls[x]],mm[rs[x]]));}inline void sr(int x){    int y=fa[x],z=fa[y];    if(lazy[z]) putdown(z);    if(lazy[y]) putdown(y);    if(lazy[x]) putdown(x);    ls[z]==y ? ls[z]=x :rs[z]=x; fa[x]=z;    ls[y]=rs[x]; fa[rs[x]]=y;    rs[x]=y; fa[y]=x;    NBHB(y),NBHB(x);}inline void sl(int x){    int y=fa[x],z=fa[y];    if(lazy[z]) putdown(z);    if(lazy[y]) putdown(y);    if(lazy[x]) putdown(x);    ls[z]==y ? ls[z]=x :rs[z]=x; fa[x]=z;    rs[y]=ls[x]; fa[ls[x]]=y;    ls[x]=y; fa[y]=x;    NBHB(y),NBHB(x);}int top,s[need];void splay(int x){    top=0;s[++top]=x;    for(int i=x;fa[i];i=fa[i]) s[++top]=fa[i];    while(top)    {        if(lazy[s[top]]) putdown(s[top]);        top--;    }    int y;    while(y=fa[x])    {        if(ls[y]==x) sr(x);        else sl(x);    }    root=x;}void insert(int d) //不用putdown,因为先建树,再操作{    if(tot==0)    {        num[root=tot=1]=d;        sum[1]=mm[1]=a[d];        si[1]=1;        ls[1]=rs[1]=fa[1]=0;        return ;    }    tot++;    int p=root;    while(true)    {        si[p]++;        sum[p]+=a[d];        mm[p]=max(mm[p],a[d]);        if(d<num[p])          if(ls[p]) p=ls[p];         else{ls[p]=tot;break;}        else          if(rs[p]) p=rs[p];         else{rs[p]=tot;break;}    }    si[tot]=1,sum[tot]=a[tot],fa[tot]=p,mm[tot]=a[d],num[tot]=d;    splay(tot);}//.............................................int k,d,l,r;int getk(int k){    int p=root;    while(true)    {        if(lazy[p]) putdown(p);        if(ls[p]&&si[ls[p]]>=k) p=ls[p];        else if(k==1||(ls[p]&&si[ls[p]]==k-1)) return p;        else {k-=si[ls[p]]+1;p=rs[p];}    }}void change(int xx){    int y;    while(fa[xx]!=root)    {        y=fa[xx];        if(lazy[y]) putdown(y);        if(lazy[xx]) putdown(xx);        if(ls[y]==xx) sr(xx);        else sl(xx);    }}int get(){    if(l>1&&r<tot)    {        int a=getk(l-1),b=getk(r+1);        splay(a);        change(b);        return ls[b];    }    else if(l>1&&r==tot)    {        int a=getk(l-1);        splay(a);        return rs[a];    }    else if(l==1&&r<tot)    {        int b=getk(r+1);        splay(b);        return ls[b];    }    else return root;}//.............................................int main(){    int n,m;scanf("%d%d",&n,&m);    for(int i=1;i<=n;i++) in_(a[i]),insert(i);    for(int i=1,b,kk;i<=m;i++)    {        in_(b);        if(b==1)        {            in_(k);            out_(a[num[getk(k)]]),putchar(10);        }        else if(b==2)        {            in_(k),in_(b);            kk=num[getk(k)];            a[kk]+=b;            splay(kk);        }        else        {            in_(l),in_(r);            kk=get();            if(b==3) out_(sum[kk]),putchar(10);            else if(b==4) out_(mm[kk]),putchar(10);            else lazy[kk]^=1;        }    }}
0 0
原创粉丝点击