#4139. 白白的(baibaide)
题意
内存限制:1024 MiB
时间限制:2000 ms
有一个长度为 $n$ 的序列 $a_1, a_2, \dots, a_n$,一开始每个位置都是白色。如果一个区间中每个位置都是白色,则称这是一个白白的区间。如果一个白白的区间向左或向右延长后都不是白白的区间了,则称这是一个极长的白白的区间。有 $q$ 次操作,每次操作会修改某个位置的值,或者把某个位置变成黑色。每次操作后,求所有极长的白白的区间中含有的逆序对数的异或和。强制在线。
$n ≤ 150000,q ≤ 20000,0 ≤ a_i ≤ 10^9,1 ≤ x ≤ n,0 ≤ y ≤ 10^9$
题解
容易想到启发式分裂,并用树状数组+主席树维护逆序对个数,可惜这样是 $O(nlog^3n)$
考虑用 $Splay$ 维护一段白白的区间,每次分裂减少一个数后所造成的影响可以通过查询其rank求出,修改数的时候就照样用树套树维护即可,效率 $O(nlog^2n+qlog^3n)$
代码
#include <bits/stdc++.h> #define mid ((l+r)>>1) #define LL long long #define I inline using namespace std; const int N=1.5e5+5,ax=1e9; set<int>st;set<int>::iterator it;LL Ans,ans[N],lst; int tt,n,q,a[N],s[N*250],ls[N*250],rs[N*250],T[N],d[N],rt[N]; int son[N*40][2],fa[N*40],sz[N*40],tot,w[N*40],cnt[N*40]; I void update(int& x,int l,int r,int p,int v){ if (!x) x=++tt;s[x]+=v; if (l==r) return; if (mid>=p) update(ls[x],l,mid,p,v); else update(rs[x],mid+1,r,p,v); } I void update(int x,int v){ for (int i=x;i<=n;i+=i&-i) update(T[i],0,ax,a[x],v); } I int query(int x,int l,int r,int L,int R){ if (!x) return 0;int res=0; if (L<=l && r<=R) return s[x]; if (mid<R) res=query(rs[x],mid+1,r,L,R); if (mid>=L) res+=query(ls[x],l,mid,L,R); return res; } I int query(int L,int R,int l,int r){ if (L>=R || l>r) return 0;int res=0; for (;R;R-=R&-R) res+=query(T[R],0,ax,l,r); for (;L;L-=L&-L) res-=query(T[L],0,ax,l,r); return res; } #define Ls son[x][0] #define Rs son[x][1] I void update(int x){sz[x]=sz[Ls]+sz[Rs]+cnt[x];} I int init(){ tot+=2;sz[tot-1]=sz[tot]=cnt[tot-1]=cnt[tot]=0; son[tot][1]=tot-1;fa[tot-1]=tot; w[tot]=-1;w[tot-1]=ax+1;return tot; } I bool iden(int x,int y){return son[y][1]==x;} I void rotate(int x){ int y=fa[x],z=fa[y],k=iden(x,y); fa[x]=z;son[z][iden(y,z)]=x; fa[son[x][k^1]]=y; son[y][k]=son[x][k^1]; fa[y]=x;son[x][k^1]=y; update(y);update(x); } I void splay(int x,int& F){ if (!x) return;F=0; while(fa[x]!=F){ int y=fa[x],z=fa[y]; if (z!=F){ if (iden(x,y)^iden(y,z)) rotate(x); else rotate(y); }rotate(x); }F=x; } I void ins(int& r,int v,int x){ int u=r,F=0; while(u && w[u]!=v) F=u,u=son[u][v>w[F]]; if (u){ splay(u,r); cnt[u]+=x;update(u); return; } fa[u=++tot]=F;w[u]=v; sz[u]=cnt[u]=1; son[u][0]=son[u][1]=0; if (F) son[F][v>w[F]]=u; splay(u,r); } I int query(int& r,int v,bool ty){ int u=r; while(u && w[u]!=v) u=son[u][v>w[u]]; splay(u,r); return sz[son[u][ty]]; } int main(){ scanf("%d%d",&n,&q); st.insert(1e9);rt[1]=init(); for (int i=1;i<=n;i++) scanf("%d",&a[i]),update(i,1), Ans+=query(0,i-1,a[i]+1,ax),ins(rt[1],a[i],1); ans[1]=Ans;st.insert(1);d[1]=n; for (int op,x,y,l,r;q--;){ LL X,Y;scanf("%d%lld",&op,&X);x=(int)(X^lst); it=st.upper_bound(x);it--;l=(*it);r=d[l];Ans^=ans[l]; if (op){ d[l]=x-1;if (x<r) d[x+1]=r,st.insert(x+1); LL A=query(l-1,x-1,a[x]+1,ax)+query(x,r,0,a[x]-1); ins(rt[l],a[x],-1); if (x-l<r-x){ rt[x+1]=rt[l];rt[l]=init(); ans[x+1]=ans[l];ans[l]=0; for (int i=l;i<x;i++) A+=query(rt[x+1],a[i],0), ins(rt[x+1],a[i],-1), ins(rt[l],a[i],1), ans[l]+=query(rt[l],a[i],1); ans[x+1]-=A;Ans^=(ans[x+1]^ans[l]); } else{ ans[x+1]=0; if (r>x) rt[x+1]=init(); for (int i=r;i>x;i--) A+=query(rt[l],a[i],1), ins(rt[l],a[i],-1), ins(rt[x+1],a[i],1), ans[x+1]+=query(rt[x+1],a[i],0); ans[l]-=A;Ans^=(ans[x+1]^ans[l]); } } else{ scanf("%lld",&Y);y=(int)(Y^lst); ins(rt[l],a[x],-1);ins(rt[l],y,1); ans[l]-=query(l-1,x-1,a[x]+1,ax); ans[l]-=query(x,r,0,a[x]-1); update(x,-1);a[x]=y;update(x,1); ans[l]+=query(l-1,x-1,a[x]+1,ax); ans[l]+=query(x,r,0,a[x]-1); Ans^=ans[l]; } printf("%lld\n",Ans);lst=Ans; } return 0; }