BZOJ1500: [NOI2005]维修数列 Splay维护序列
//#include<bits/stdc++.h> //#pragma comment(linker, "/STACK:1024000000,1024000000") #include<stdio.h> #include<algorithm> #include<queue> #include<string.h> #include<iostream> #include<math.h> #include<set> #include<map> #include<vector> #include<iomanip> #include<bitset> using namespace std; // #define ll long long #define pb push_back #define FOR(a) for(int i=1;i<=a;i++) #define sqr(a) (a)*(a) #define dis(a,b) sqrt(sqr(a.x-b.x)+sqr(a.y-b.y)) ll qp(ll a,ll b,ll mod){ ll t=1;while(b){if(b&1)t=t*a%mod;b>>=1;a=a*a%mod;}return t; } struct DOT{int x;int y;}; const int dx[4]={0,0,-1,1}; const int dy[4]={1,-1,0,0}; const int inf=0x3f3f3f3f; const ll mod=1e9+7; const int maxn=5e5+6; int n,m; int a[maxn]; int rt=0; int c[maxn][2],parent[maxn]; int val[maxn],size[maxn]; int lx[maxn],rx[maxn],mx[maxn],sum[maxn]; int tag[maxn],rev[maxn]; int id[maxn]; queue<int>Q; inline void pushup(int x){ int l=c[x][0],r=c[x][1]; size[x]=size[l]+size[r]+1; //子树大小 sum[x]=sum[l]+sum[r]+val[x]; //区间和 mx[x]=max(max(mx[r],mx[l]),val[x]+rx[l]+lx[r]); //最大子段和 lx[x]=max(lx[l],sum[l]+val[x]+lx[r]); //最大前缀 rx[x]=max(rx[r],sum[r]+val[x]+rx[l]); //最大后缀 } void pushdown(int x){ int l=c[x][0],r=c[x][1]; if(tag[x]){ tag[x]=rev[x]=0; if(l)tag[l]=1,val[l]=val[x],sum[l]=val[x]*size[l]; if(r)tag[r]=1,val[r]=val[x],sum[r]=val[x]*size[r]; if(val[x]>=0){ if(l)lx[l]=rx[l]=mx[l]=sum[l]; if(r)lx[r]=rx[r]=mx[r]=sum[r]; }else{ if(l)lx[l]=rx[l]=0;mx[l]=val[x]; if(r)lx[r]=rx[r]=0,mx[r]=val[x]; } } if(rev[x]){ rev[x]=0;rev[l]^=1;rev[r]^=1; swap(lx[l],rx[l]);swap(lx[r],rx[r]); swap(c[l][0],c[l][1]);swap(c[r][0],c[r][1]); } } void rotate(int x,int &k){ int y=parent[x],z=parent[y],d=c[y][1]==x; if(y==k)k=x;else c[z][c[z][1]==y]=x;parent[x]=z; c[y][d]=c[x][d^1];parent[c[x][d^1]]=y; c[x][d^1]=y;parent[y]=x; pushup(y);pushup(x); } void splay(int x,int &k){ while(x!=k){ int y=parent[x],z=parent[y]; if(y!=k) (c[y][0]==x^c[z][0]==y)?rotate(x,k):rotate(y,k); rotate(x,k); } } inline int find(int x,int k){ pushdown(x); int lc=c[x][0],rc=c[x][1]; if(k>size[lc]+1)return find(rc,k-size[lc]-1); else if(k<=size[lc])return find(lc,k); else return x; } inline int Split(int l,int r){ int x=find(rt,l); int y=find(rt,r); splay(x,rt);splay(y,c[x][1]); return c[y][0]; } void init(){for(int i=n+3;i<maxn;i++)Q.push(i);} inline void recycle(int x){ int &l=c[x][0],&r=c[x][1]; if(l)recycle(l);if(r)recycle(r); Q.push(x); parent[x]=l=r=tag[x]=rev[x]=0; } void erase(int l,int r){ int x=Split(l,r),y=parent[x]; recycle(x); c[y][0]=0;pushup(y);pushup(parent[y]); } void build(int l,int r,int f){ if(l>r)return; int m=l+r>>1,now=id[m],pa=id[f]; val[now]=a[m];parent[now]=pa; c[pa][m>=f]=now; if(l==r){ mx[now]=sum[now]=val[now]; lx[now]=rx[now]=max(0,val[now]); size[now]=1; return; } build(l,m-1,m);build(m+1,r,m); pushup(now); } void insert(int l,int tot){ for(int i=1;i<=tot;i++)scanf("%d",&a[i]); for(int i=1;i<=tot;i++)id[i]=Q.front(),Q.pop(); build(1,tot,0); int z=id[1+tot>>1],x=find(rt,l+1),y=find(rt,l+2); //标号右移 splay(x,rt);splay(y,c[x][1]); parent[z]=y;c[y][0]=z; pushup(y);pushup(x); } int query(int l,int r){ int x=Split(l,r); return sum[x]; } void rever(int l,int r){ int x=Split(l,r),y=parent[x]; if(!tag[x]){ rev[x]^=1; swap(c[x][0],c[x][1]); swap(lx[x],rx[x]); pushup(y);pushup(parent[y]); } } void update(int l,int r,int v){ int x=Split(l,r),y=parent[x]; val[x]=v;tag[x]=1;sum[x]=size[x]*v; if(v>=0)lx[x]=rx[x]=mx[x]=sum[x]; else lx[x]=rx[x]=0,mx[x]=v; pushup(y);pushup(parent[y]); } char s[20]; int main(){ scanf("%d%d",&n,&m); mx[0]=a[1]=a[n+2]=-inf; for(int i=1;i<=n;i++){ scanf("%d",&a[i+1]); } for(int i=1;i<=n+2;i++)id[i]=i; init(); build(1,n+2,0);rt=n+3>>1; for(int i=1;i<=m;i++){ scanf("%s",s); if(s[2]=='X')printf("%d\n",mx[rt]); else{ int k,tot;scanf("%d",&k);scanf("%d",&tot); if(s[2]=='S')insert(k,tot); if(s[2]=='L')erase(k,k+tot+1); if(s[2]=='K'){int x;scanf("%d",&x);update(k,k+tot+1,x);} if(s[2]=='V')rever(k,k+tot+1); if(s[2]=='T')printf("%d\n",query(k,k+tot+1)); } } }
通过split提取目标区间,由于旋转到根影响的父节点就2个
支持O(logn)区间反转,O(元素个数)加入元素
回收节点编号的操作挺棒的,以后不用担心数组版数据结构溢编号了