洛谷P2710 数列

该博客介绍了洛谷P2710数列问题,涉及7种不同的操作,如插入、删除、翻转、统一修改等。文章重点讨论了在处理区间操作时的splay树标记传递和旋转的难点,特别是旋转标记部分。作者分享了自己的解题思路,包括错误尝试和最终正确的代码实现,并指出在信息学竞赛中,有时不必深究证明,能正确AC即可。
摘要由CSDN通过智能技术生成

题目描述

维护一个数列,共7种操作:

1 INSERT x n a1 a2 .. An

在第x个数后插入n个数分别为a1 .. an;

2 DELETE x n

删除第x个数开始的n个数;

3 REVERSE x n

翻转第x个数开始的n个数的区间;

4 MAKE-SAME x n t

将第x个数开始的n个数统一改为t;

5 GET-SUM x n

输出第x个数开始的n个数的和;

6 GET x

输出第x个数的值;

7 MAX-SUM x n

输出第x个数开始的n个数的最大连续子序列和。

输入输出格式

输入格式:

第1行为N,M,N表示初始序列中数的个数,M表示操作的个数。

第2行为N个数a1 .. An,表示初始序列。

第3行到第M+2行,每行一个操作。

输出格式:

输出5 GET-SUM,6 GET,7 MAX-SUM操作的结果。

输入输出样例

输入样例#1: 
9 8
2 -6 3 5 1 -5 -3 6 3
GET-SUM 5 4
MAX-SUM 1 9
INSERT 8 3 -5 7 2
DELETE 12 1
MAKE-SAME 3 3 2
REVERSE 3 6
GET 5
MAX-SUM 1 11
输出样例#1: 
-1
10
-5
10

说明

共20组数据,每组数据随机生成,保证每个时刻数列里的数不超过200000个,任何一个输入的数字均在-1000~1000之间,结果不超过2^30。

第1~2组1≤N≤51≤M≤10

第3~4组1≤N≤101≤M≤20

第5~6组1≤N≤201≤M≤50

第7~8组1≤N≤501≤M≤100

第9~10组1≤N≤1001≤M≤500

第11~12组1≤N≤10001≤M≤1000

第13~14组1≤N≤50001≤M≤2000

第15~16组1≤N≤10000  1≤M≤5000

第17~18组1≤N≤100000  1≤M≤10000

第19~20组1≤N≤200000  1≤M≤20000

与 [NOI2005]维护数列 差不多,只不过多了一个操作。

splay没话说,什么区间 [ l , r ] ,要将 l-1 , r+1 旋转到根,就不讲了,简单。

标记下传:

其他还好,旋转标记极坑!

这坑了我半天,到现在也没想出为啥,只知道是对的。。。

代码应该是:

    if(a[rt].flag){
        if(a[rt].son[0]){
			a[a[rt].son[0]].flag^=1;
        	swap(a[a[rt].son[0]].suml,a[a[rt].son[0]].sumr);
			swap(a[a[rt].son[0]].son[0],a[a[rt].son[0]].son[1]);
		}
		if(a[rt].son[1]){
			a[a[rt].son[1]].flag^=1;
        	swap(a[a[rt].son[1]].suml,a[a[rt].son[1]].sumr);
			swap(a[a[rt].son[1]].son[0],a[a[rt].son[1]].son[1]);
		}
		a[rt].flag^=1;
    }

而不是:

if(a[rt].flag){
        a[a[rt].son[0]].flag^=1;a[a[rt].son[1]].flag^=1;a[rt].flag^=1;
        swap(a[rt].suml,a[rt].sumr);swap(a[rt].son[0],a[rt].son[1]);
    }

于是打标记就是:

void reverge(int rt,int l,int r){
    int front=kth(rt,l),next=kth(rt,r+2);
	split(front,next);
	int k=a[next].son[0];
    if(!k)return;
	a[k].flag^=1;
    swap(a[k].son[0],a[k].son[1]);
	swap(a[k].suml,a[k].sumr);
    pushup(next);pushup(front);
}

虽然不知道为什么,但是AC了,于是:

信息学竞赛不需要证明。。。

附上超长代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<queue>
#define MAXN 500010
#define MAX 999999999
using namespace std;
queue<int> q;
int n,m,size=1,root,val[MAXN];
struct node{
    int f,s,flag,set,son[2];
    int v,w,sum,suml,sumr;
}a[MAXN];
inline int read(){
    int date=0,w=1;char c=0;
    while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
    while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
    return date*w;
}
inline void clean(int rt){
    a[rt].son[0]=a[rt].son[1]=a[rt].f=a[rt].s=a[rt].flag=a[rt].v=a[rt].w=0;
    a[rt].sum=a[rt].suml=a[rt].sumr=-MAX;
}
inline void pushup(int rt){
    if(!rt)return;
    a[rt].s=a[a[rt].son[0]].s+a[a[rt].son[1]].s+1;
    a[rt].w=a[a[rt].son[0]].w+a[a[rt].son[1]].w+a[rt].v;
    a[rt].suml=max(a[a[rt].son[0]].suml,a[a[rt].son[0]].w+a[rt].v+max(0,a[a[rt].son[1]].suml));
    a[rt].sumr=max(a[a[rt].son[1]].sumr,a[a[rt].son[1]].w+a[rt].v+max(0,a[a[rt].son[0]].sumr));
    a[rt].sum=max(a[rt].v+max(0,a[a[rt].son[0]].sumr)+max(0,a[a[rt].son[1]].suml),max(a[a[rt].son[0]].sum,a[a[rt].son[1]].sum));
}
inline void pushdown(int rt){
    if(!rt)return;
    if(a[rt].set!=-MAX){
        if(a[rt].son[0]){
            a[a[rt].son[0]].set=a[a[rt].son[0]].v=a[rt].set;
            a[a[rt].son[0]].w=a[rt].set*a[a[rt].son[0]].s;
            a[a[rt].son[0]].suml=a[a[rt].son[0]].sumr=a[a[rt].son[0]].sum=max(a[a[rt].son[0]].set,a[a[rt].son[0]].w);
        }
        if(a[rt].son[1]){
            a[a[rt].son[1]].set=a[a[rt].son[1]].v=a[rt].set;
            a[a[rt].son[1]].w=a[rt].set*a[a[rt].son[1]].s;
            a[a[rt].son[1]].suml=a[a[rt].son[1]].sumr=a[a[rt].son[1]].sum=max(a[a[rt].son[1]].set,a[a[rt].son[1]].w);
        }
        a[rt].set=-MAX;
        a[rt].flag=0;
    }
    if(a[rt].flag){
        if(a[rt].son[0]){
            a[a[rt].son[0]].flag^=1;
        	swap(a[a[rt].son[0]].suml,a[a[rt].son[0]].sumr);
            swap(a[a[rt].son[0]].son[0],a[a[rt].son[0]].son[1]);
        }
        if(a[rt].son[1]){
            a[a[rt].son[1]].flag^=1;
        	swap(a[a[rt].son[1]].suml,a[a[rt].son[1]].sumr);
            swap(a[a[rt].son[1]].son[0],a[a[rt].son[1]].son[1]);
        }
        a[rt].flag^=1;
    }
}
inline int newnode(int x){
    int rt;
    if(q.empty())rt=size++;
    else{
        rt=q.front();
        q.pop();
    }
    a[rt].v=x;
    a[rt].suml=a[rt].sumr=a[rt].sum=-MAX;
    a[rt].flag=0;a[rt].set=-MAX;
    return rt;
}
inline void turn(int rt,int k){
    int x=a[rt].f,y=a[x].f;
    pushdown(x);pushdown(rt);
    a[x].son[k^1]=a[rt].son[k];
    if(a[rt].son[k])a[a[rt].son[k]].f=x;
    a[rt].f=y;
    if(y)a[y].son[a[y].son[1]==x]=rt;
    a[x].f=rt;
    a[rt].son[k]=x;
    pushup(x);pushup(rt);
}
void splay(int rt,int ancestry){
    while(a[rt].f!=ancestry){
        int x=a[rt].f,y=a[x].f;
        if(y==ancestry)turn(rt,a[x].son[0]==rt);
        else{
            int k=a[y].son[0]==x?1:0;
            if(a[x].son[k]==rt){turn(rt,k^1);turn(rt,k);}
            else{turn(x,k);turn(rt,k);}
        }
    }
    if(ancestry==0)root=rt;
}
int kth(int rt,int k){
    if(a[rt].s<k)return 0;
    while(1){
        pushdown(rt);
        int y=a[rt].son[0];
        if(k>a[y].s+1){
            rt=a[rt].son[1];
            k-=a[y].s+1;
        }
        else if(k<=a[y].s)rt=y;
        else return rt;
    }
}
int buildtree(int l,int r){
    if(l>r)return 0;
    int rt,mid=l+r>>1,lson=0,rson=0;
    lson=buildtree(l,mid-1);
    rt=newnode(val[mid]);
    rson=buildtree(mid+1,r);
    a[rt].son[0]=lson;
    a[rt].son[1]=rson;
    if(lson)a[lson].f=rt;
    if(rson)a[rson].f=rt;
    pushup(rt);
    return rt;
}
inline void split(int front,int next){
    splay(front,0);splay(next,front);
}
inline void insert(int rt,int x,int y){
    int front=kth(rt,x+1),next=kth(rt,x+2);
    split(front,next);
    int k=a[next].son[0];
    rt=buildtree(1,y);
    a[next].son[0]=rt;a[rt].f=next;
    pushup(next);pushup(front);
}
void delete_x(int rt){
    if(!rt)return;
    q.push(rt);
    if(a[rt].son[0])delete_x(a[rt].son[0]);
    if(a[rt].son[1])delete_x(a[rt].son[1]);
    clean(rt);
}
inline void remove(int rt,int l,int r){
    int front=kth(rt,l),next=kth(rt,r+2);
    split(front,next);
    int k=a[next].son[0];
    if(k)delete_x(k);
    a[next].son[0]=0;
    pushup(next);pushup(front);
}
void reverge(int rt,int l,int r){
    int front=kth(rt,l),next=kth(rt,r+2);
    split(front,next);
    int k=a[next].son[0];
    if(!k)return;
    a[k].flag^=1;
    swap(a[k].son[0],a[k].son[1]);
    swap(a[k].suml,a[k].sumr);
    pushup(next);pushup(front);
}
void same(int rt,int l,int r,int x){
    int front=kth(rt,l),next=kth(rt,r+2);
    split(front,next);
    int k=a[next].son[0];
    if(!k)return;
    a[k].set=a[k].v=x;
    a[k].w=x*a[k].s;
    a[k].suml=a[k].sumr=a[k].sum=max(x,a[k].w);
    pushup(next);pushup(front);
}
int main(){
    int x,y,k;
    char ch[20];
    n=read();m=read();
    for(int i=1;i<=n;i++)val[i]=read();
    val[0]=val[n+1]=0;
    clean(0);clean(n+1);
    root=buildtree(0,n+1);
    while(m--){
        scanf("%s",ch);x=read();
        switch(ch[0]){
            case 'I':{
                y=read();
                for(int i=1;i<=y;i++)val[i]=read();
                insert(root,x,y);
                break;
            }
            case 'D':y=read();remove(root,x,x+y-1);break;
            case 'R':y=read();reverge(root,x,x+y-1);break;
            case 'G':{
                if(ch[3]=='-'){
                    y=read();
    				int front=kth(root,x),next=kth(root,x+y+1);
                    split(front,next);
                    int k=a[next].son[0];
                    printf("%d\n",a[k].w);
                }
                else printf("%d\n",a[kth(root,x+1)].v);
                break;
            }
            case 'M':{
                y=read();
                if(ch[4]=='-'){
                	k=read();
                	same(root,x,x+y-1,k);
                }
                else{
    				int front=kth(root,x),next=kth(root,x+y+1);
                    split(front,next);
                    int k=a[next].son[0];
                    printf("%d\n",a[k].sum);
                }
                break;
            }
        }
    }
    return 0;
}

    clean(rt);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值