这题号称是noi出过最变态的数据结构题,,感觉还差不多嘛。。一开始我一直在纠结splay上的节点一点要有一个key值的啊,要是以这个数在序列中的位置作为key值的话又要插入又要删除肯定弄不了。。然后想了很久突然顿悟。。貌似我给一个初始顺序以后是不用访问key的&&找第k位的数只要写一个findkth就行了嘛。。(当时太弱)
然后我就一口气写了下来。。
对每个节点维护size,sum,maxsum,maxpre,maxpos(这两个用于更新maxsum),same,rev(这两个是lazy标记)。
更新maxsum考虑3种情况,一是左儿子的maxsum,二是右儿子的maxsum,三是左儿子的maxpos+自身num+右儿子maxpre,这里maxpre和maxpos更新的时候是可以一个都不要也就是为0的,我就在这里被坑了。。
1. 初始或者插入的时候建树用类似线段树的二分的方法,然后把pos转到root,把pos+1转到root下,只要把数挂在pos+1的左儿子下就行了。。这里有一个关于findkth的问题,为了方便处理边界我一开始插入了一个头结点和一个尾结点,findkth的时候要小心头结点的存在。。
2. 删除的时候把pos转到root,pos+tot+1转到root下,pos+tot+1的左儿子就是要删除的区间,直接删去即可。。这里要注意一个回收内存的问题,要把删去的结点放到一个栈里,newnode的时候优先从这个栈里拿结点,这样既可以节省内存又可以节省时间。。
3. 修改和翻转的时候找出区间打上标记就行。
4. getsum找出区间直接输出答案,maxsum直接输出root的答案。
打到这里最原始的程序就写完了,但是我一开始在处理标记的时候只是单纯的打上标记没有更新维护的东西,导致每次输出答案必须遍历子树更新答案,时间复杂度没有了保证。。然后我看黄学长的代码发现打标记的时候要把信息及时维护一下,一加上去速度瞬间就快了起来。。(当时太弱)
第二个坑点是一开始插入的头结点尾结点的值要是-inf不能是0,否则maxsum更新时会出错。。
最后就是same标记的问题,要特殊处理一下makesame(0)的情况。。
到这里就搞定了,6052MSAC,有点慢。。
#include<iostream>
#include<cstdio>
#include<memory.h>
using namespace std;
const int inf=99999999,maxn=500005;
int n,m,i,nnode=0,rest=0,root=0,root1,pos,tot,k,q[maxn],c[maxn][2],size[maxn],pre[maxn],num[maxn],maxsum[maxn],maxpre[maxn],maxpos[maxn],same[maxn],rev[maxn],sum[4000005],s[maxn];
char str[10];
void update(int x)
{
size[x]=size[c[x][0]]+size[c[x][1]]+1;sum[x]=sum[c[x][0]]+sum[c[x][1]]+num[x];
maxsum[x]=max(max(maxsum[c[x][0]],maxsum[c[x][1]]),maxpos[c[x][0]]+num[x]+maxpre[c[x][1]]);
maxpre[x]=max(sum[c[x][0]]+maxpre[c[x][1]]+num[x],maxpre[c[x][0]]);maxpos[x]=max(sum[c[x][1]]+maxpos[c[x][0]]+num[x],maxpos[c[x][1]]);
}
void marksame(int x,int c)
{
same[x]=c;
if (c==1001) c=0;
num[x]=c;sum[x]=size[x]*c;
if (c>=0) maxsum[x]=maxpre[x]=maxpos[x]=size[x]*c; else maxpre[x]=maxpos[x]=0,maxsum[x]=c;
}
void markrev(int x)
{
swap(c[x][0],c[x][1]);
swap(maxpre[x],maxpos[x]);
rev[x]^=1;
}
void down(int x)
{
if (same[x])
{
if (c[x][0]) marksame(c[x][0],same[x]); if (c[x][1]) marksame(c[x][1],same[x]);
same[x]=0;
}
if (rev[x])
{
if (c[x][0]) markrev(c[x][0]);if (c[x][1]) markrev(c[x][1]);
rev[x]=0;
}
}
void newnode(int &x,int fa,int k)
{
if (rest) x=s[rest--];else x=++nnode;
pre[x]=fa;num[x]=k; size[x]=1;
c[x][0]=c[x][1]=same[x]=rev[x]=0;
sum[x]=maxsum[x]=k;
maxpre[x]=maxpos[x]=max(k,0);
}
void rot(int x,int kind)
{
int y=pre[x];int z=pre[y];down(x);
c[y][!kind]=c[x][kind];pre[c[x][kind]]=y;
c[x][kind]=y;pre[y]=x;
pre[x]=z;if (z) c[z][c[z][1]==y]=x;
update(y);update(x);if (z) update(z);
}
void splay(int x,int goal)
{
int y,z,kind;
while (pre[x]!=goal)
{
y=pre[x];down(y);
if (pre[y]==goal) rot(x,c[y][0]==x);
else
{
z=pre[y];down(z);kind=c[z][0]==y;
if (c[y][!kind]==x) rot(y,kind);else rot(x,!kind);
rot(x,kind);
}
}
if (goal==0) root=x;
}
int findkth(int x,int k)//加处理
{
down(x);
if (size[c[x][0]]>=k) return findkth(c[x][0],k);
if (k==size[c[x][0]]+1) return x;
if (k>size[c[x][0]]+1) return findkth(c[x][1],k-size[c[x][0]]-1);
}
void build(int &x,int fa,int l,int r)
{
if (l>r) return;
int mid=(l+r)/2;
newnode(x,fa,q[mid]);
if (l==r) return;
build(c[x][0],x,l,mid-1);build(c[x][1],x,mid+1,r);
update(x);
}
void insert(int pos,int tot)
{
int i;
for (i=1;i<=tot;i++)
scanf("%d",&q[i]);
build(root1,0,1,tot);
splay(findkth(root,pos+1),0);
splay(findkth(root,pos+2),root);
c[c[root][1]][0]=root1;pre[root1]=c[root][1];
update(c[root][1]);update(root);
}
void erase(int x)
{
if (!x) return;
s[++rest]=x;
erase(c[x][0]);erase(c[x][1]);
}
void deleted(int pos,int tot)
{
splay(findkth(root,pos),0);splay(findkth(root,pos+tot+1),root);
erase(c[c[root][1]][0]);
c[c[root][1]][0]=0;
update(c[root][1]);update(root);
}
void makesame(int pos,int tot,int k)
{
if (k==0) k=1001;
splay(findkth(root,pos),0);splay(findkth(root,pos+tot+1),root);
marksame(c[c[root][1]][0],k);
update(c[root][1]);update(root);
}
void markrev(int pos,int tot)
{
splay(findkth(root,pos),0);splay(findkth(root,pos+tot+1),root);
markrev(c[c[root][1]][0]);
update(c[root][1]);update(root);
}
int getsum(int pos,int tot)
{
splay(findkth(root,pos),0);splay(findkth(root,pos+tot+1),root);
return sum[c[c[root][1]][0]];
}
void print(int x)
{
if (c[x][0]) print(c[x][0]);
printf("%d->num:%d,fa:%d,lc:%d,rc:%d,size:%d,sum:%d,maxpre:%d,maxpos:%d,maxsum:%d,same:%d,rev:%d\n",x,num[x],pre[x],c[x][0],c[x][1],size[x],sum[x],maxpre[x],maxpos[x],maxsum[x],same[x],rev[x]);
if (c[x][1])print(c[x][1]);
}
int main()
{
freopen("shulie.in","r",stdin);
freopen("my.out","w",stdout);
scanf("%d%d",&n,&m);
newnode(root,0,-inf);newnode(c[root][1],root,-inf);
insert(0,n);
size[0]=pre[0]=same[0]=rev[0]=num[0]=sum[0]=maxpre[0]=maxpos[0]=0;maxsum[0]=-inf;
for (i=1;i<=m;i++)
{
scanf("%s",&str);
if (str[2]!='X') scanf("%d%d",&pos,&tot); else printf("%d\n",maxsum[root]);
if (str[0]=='I') insert(pos,tot);
if (str[0]=='D') deleted(pos,tot);
if (str[0]=='M'&&str[2]=='K') scanf("%d",&k),makesame(pos,tot,k);
if (str[0]=='R') markrev(pos,tot);
if (str[0]=='G') printf("%d\n",getsum(pos,tot));
}
}