bzoj1500

Description

Input

输入的第1 行包含两个数N 和M(M ≤20 000),N 表示初始时数列中数的个数,M表示要进行的操作数目。
第2行包含N个数字,描述初始时的数列。
以下M行,每行一条命令,格式参见问题描述中的表格。
任何时刻数列中最多含有500 000个数,数列中任何一个数字均在[-1 000, 1 000]内。
插入的数字总数不超过4 000 000个,输入文件大小不超过20MBytes。

Output

对于输入数据中的GET-SUM和MAX-SUM操作,向输出文件依次打印结果,每个答案(数字)占一行。

Sample Input

9 8
2 -6 3 5 1 -5 -3 6 3
GET-SUM 5 4
MAX-SUM
INSERT 8 3 -5 7 2
DELETE 12 1
MAKE-SAME 3 3 2
REVERSE 3 6
GET-SUM 5 4
MAX-SUM

Sample Output

-1
10
1
10

这题是裸的平衡树。不过我却调了很久,果然还是太渣。

最大和子序列比较难维护,我是先维护LMAX表示从左边起区间的连续最大和,RMAX表示从右边起区间的连续最大和,然后SUM1(最大和子序列)就是等于MAX(SUM1[LC[X]],SUM1[RC[X]],LMAX[RC[X]]+KEY[X]+RMAX[LC[X]])

其他的好像都不难,记得插入的时候不要一个一个插

很明显我们要设定2个标记,翻转的时候交换左右儿子,记住这时候要交换LMAX和RMAX,最后注意下区间覆盖可能为0,因为这个我调了好久......

好了废话不说附上代码:

#include<algorithm>  
#include<iostream>  
#include<cstring>  
#include<cstdio>  
#include<cmath>  
using namespace std;  
const int MAXX=500100;  
int fa[MAXX],lc[MAXX],rc[MAXX],root,lmax[MAXX],sum[MAXX],rmax[MAXX],sum1[MAXX];  
int fan[MAXX],cnt[MAXX],lentag[MAXX],len,qq[MAXX],top=0,sbt=0,size[MAXX],key[MAXX];  
int a[MAXX],i,j,k,l,n,m,x,y,z,num;  
char s[15];  
int get()  
{  
    char c;  
    while (((c=getchar())<48||c>57)&&c!='-');  
    if (c=='-')  
    {  
        int res=0;  
        while ((c=getchar())>=48&&c<=57)  
        res=res*10+c-'0';  
        return -res;  
    }  
    else{  
        int res=c-'0';  
        while ((c=getchar())>=48&&c<=57)  
        res=res*10+c-'0';  
        return res;  
    }  
}  
void pushup(int y)  
{  
    int lson=lc[y],rson=rc[y];  
    size[y]=size[lson]+size[rson]+1;  
    sum[y]=sum[lson]+sum[rson]+key[y];  
    lmax[y]=max(lmax[lson],sum[lson]+key[y]+max(0,lmax[rson]));  
    rmax[y]=max(rmax[rson],sum[rson]+key[y]+max(0,rmax[lson]));  
    sum1[y]=max(sum1[lson],sum1[rson]);  
    sum1[y]=max(max(rmax[lson],0)+key[y]+max(lmax[rson],0),sum1[y]);  
}  
void turn(int x)  
{  
    int y=fa[x],z=fa[y],b=0;  
    if (x==lc[y]) b=rc[x];  
    else b=lc[x];  
    if (b) fa[b]=y;  
    fa[x]=z;fa[y]=x;  
    if (z)  
        if (lc[z]==y) lc[z]=x;  
        else rc[z]=x;  
    if (x==lc[y]) rc[x]=y,lc[y]=b;  
    else lc[x]=y,rc[y]=b;  
    pushup(y);  
}  
void putdown1(int x,int y)  
{  
    sum[x]=size[x]*y;  
    key[x]=y;  
    if (y<=0) lmax[x]=rmax[x]=sum1[x]=y;  
    else lmax[x]=rmax[x]=sum1[x]=y*size[x];  
    cnt[x]=1;  
}  
void rev(int x)  
{  
    swap(lmax[x],rmax[x]);  
    swap(lc[x],rc[x]);  
    fan[x]^=1;  
}  
void putdown(int x)  
{  
	int lson=lc[x],rson=rc[x],w=key[x];
    if (fan[x])  
    {  
        if (lson) rev(lson);  
        if (rson) rev(rson);  
        fan[x]=0;  
    }  
    if (cnt[x])  
    {  
        if (lson) putdown1(lson,w);  
        if (rson) putdown1(rson,w);  
        cnt[x]=0;  
    }  
}  
void splay(int x,int y)  
{  
    /*len=0;  
    for(int i=x;i;i=fa[i])  
    lentag[++len]=i;  
    while (len) putdown(lentag[len--]);  */
    while (fa[x]!=y)  
    {  
        if (fa[fa[x]]!=y)  
            if ((lc[fa[x]]==x)==(lc[fa[fa[x]]]==fa[x])) turn(fa[x]);  
            else turn(x);  
        turn(x);  
    }  
    pushup(x);  
    if (!y) root=x;  
}  
int find(int k,int p)  
{  
    while (p!=size[lc[k]]+1)
    {
    	putdown(k);
    	if (p>size[lc[k]]+1)
    		p=p-size[lc[k]]-1,k=rc[k];
    	else k=lc[k];
	}
	putdown(k);
	return k;
}  
void start(int p,int q,int &k,int yy)  
{  
    if (p>q) return;  
    if (!k)  
    {  
        if (top) k=qq[top--];  
        else k=++sbt;  
    }  
    int mid=(p+q)>>1;  
    key[k]=a[mid];  
    fa[k]=yy;  
    start(p,mid-1,lc[k],k);  
    start(mid+1,q,rc[k],k);  
    pushup(k);  
}  
void shouji(int k)  
{  
    if (!k) return;  
    qq[++top]=k;
    shouji(lc[k]); 
    shouji(rc[k]); 
    key[k]=fa[k]=lc[k]=rc[k]=sum[k]=size[k]=cnt[k]=fan[k]=0;  
    lmax[k]=rmax[k]=sum1[k]=-707406378;  
}  
int main()  
{  
    n=get();m=get();  
    memset(lmax,-127/3,sizeof(lmax));  
    memset(rmax,-127/3,sizeof(rmax));  
    memset(sum1,-127/3,sizeof(sum1));  
    for(i=1;i<=n;i++)  
    a[i]=get();  
    start(0,n+1,root,0);  
    root=1;  
    for(i=1;i<=m;i++)  
    {  
        scanf("%s",s);  
        if (s[0]=='I') //加数   
        {  
            x=get();y=get();  
            for(j=1;j<=y;j++)  
            a[j]=get();  
            int k=find(root,x+1);  
            int kk=find(root,x+2);  
            splay(k,0);splay(kk,k);  
            start(1,y,lc[kk],kk);  
            pushup(kk);  
            pushup(k);  
        }  
        if (s[0]=='D') //删数   
        {  
            x=get();y=get();  
            int k=find(root,x);  
            int kk=find(root,x+y+1);  
            splay(k,0);splay(kk,k);  
            shouji(lc[kk]);  
            lc[kk]=0;  
            pushup(kk);  
            pushup(k);  
        }  
        if (s[0]=='M'&&s[2]=='K')  //区间覆盖   
        {  
            x=get();y=get();z=get();  
            int k=find(root,x);  
            int kk=find(root,x+1+y);  
            splay(k,0);splay(kk,k);  
            putdown1(lc[kk],z);  
            pushup(kk);  
            pushup(k);  
        }  
        if (s[0]=='R') //区间翻转   
        {  
            x=get();y=get();  
            int k=find(root,x);  
            int kk=find(root,x+1+y);  
            splay(k,0);splay(kk,k);  
            if (lc[kk]&&!fan[lc[kk]]) rev(lc[kk]);  
            pushup(kk);  
            pushup(k);  
        }  
        if (s[0]=='G') //和   
        {  
            x=get();y=get();  
            int k=find(root,x);  
            int kk=find(root,x+y+1);  
            splay(k,0);splay(kk,k);  
            printf("%d\n",sum[lc[kk]]);  
        }  
        if (s[0]=='M'&&s[2]=='X') //最大和   
        {  
            int k=find(root,1);  
            int kk=find(root,size[root]);
            splay(k,0);splay(kk,k);  
            printf("%d\n",sum1[lc[kk]]);  
        }  
    }  
}  


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值