白白的(baibaide)——树状数组套主席树+splay
题目
【题目描述】
有一个长度为 $n$ 的序列 $a_1, a_2, \dots, a_n$,一开始每个位置都是白色。如果一个区间中每个位置都是白色,则称这是一个白白的区间。如果一个白白的区间向左或向右延长后都不是白白的区间了,则称这是一个极长的白白的区间。有 $q$ 次操作,每次操作会修改某个位置的值,或者把某个位置变成黑色。每次操作后,求所有极长的白白的区间中含有的逆序对数的异或和。强制在线。
【输入格式】
第一行两个正整数 $n, q$。
第二行 $n$ 个正整数 $a_1, a_2, \dots, a_n$。
接下来 $q$ 行,每行表示一次操作,每行的第一个数表示操作的种类:
$• ~ 0 ~ x ~ y$ 表示把 $a_x$ 改为 $y$
$• ~ 1 ~ x$ 表示把第 $x$ 个位置变成黑色
保证每次操作时的第 $x$ 个位置是白色的。
$x$ 和 $y$ 需要异或上一次输出的答案(若是第一次操作则无需异或)。
【输出格式】
$q$ 行,每行一个整数,表示每次询问的答案。
【样例输入】
4 3
6 0 10 1
1 2
1 0
1 2
【样例输出】
1
1
0
【数据范围与提示】
$n ≤ 150000,q ≤ 20000,0 ≤ a_i ≤ 10^9,1 ≤ x ≤ n,0 ≤ y ≤ 10^9$
$Subtask1(10pts) : n ≤ 10^3, q ≤ 10^3$
$Subtask2(20pts) : 只有 0 操作$
$Subtask3(30pts) : 只有 1 操作$
$Subtask4(40pts) : 没有特殊限制$
题解
这是一道极其毒瘤的数据结构题
求一段区间的逆序对个数,自然是用树状数组,但要支持修改和分裂,那么就套主席树,启发式分裂
效率:$ O(nlog^3n) $,很遗憾,这样子常数太大,而且这道题卡常
出题人发现,其实修改和分裂是可以分开做的
修改时直接在树套树上查询和修改即可,至于分裂时,其实要找的只有在它前面比它大的个数,可以每一个区间开一个 splay 查询,类似于启发式,暴力删,然后重构一个新的 splay
其实就是利用分裂时的特殊性质用 splay 优化树套树的分裂过程
大概要分讨一下前面的区间和后面的区间的大小
时间效率:$ O(nlog^2n)$
写到醉生梦死
代码
1 #include<bits/stdc++.h> 2 #define LL long long 3 #define _(d) while(d(isdigit(ch=getchar()))) 4 using namespace std; 5 int R(){ 6 int x;bool f=1;char ch;_(!)if(ch=='-')f=0;x=ch^48; 7 _()x=(x<<3)+(x<<1)+(ch^48);return f?x:-x;} 8 const int N=2e5+5,INF=1e9+7; 9 int n,q,a[N],Rt[N],li[N]; 10 LL ans,las,sum[N]; 11 set<int>s; 12 set<int>::iterator it; 13 class Splay{ 14 private: 15 #define Ls(x) ch[x][0] 16 #define Rs(x) ch[x][1] 17 public: 18 int val[N*40],fa[N*40],siz[N*40],num[N*40],ch[N*40][2],cnt; 19 void pushup(int x){siz[x]=siz[Ls(x)]+siz[Rs(x)]+num[x];} 20 int init(){ 21 cnt+=2; 22 fa[cnt]=cnt-1,Rs(cnt-1)=cnt; 23 val[cnt]=INF,val[cnt-1]=0; 24 siz[cnt]=siz[cnt-1]=num[cnt]=num[cnt-1]=0; 25 return cnt-1; 26 } 27 int find_xi(int rt,int x){ 28 if(!rt)return 0; 29 if(val[rt]==x)return rt; 30 if(val[rt]<x){ 31 int f=find_xi(Rs(rt),x); 32 return f?f:rt; 33 } 34 return find_xi(Ls(rt),x); 35 } 36 int find_da(int rt,int x){ 37 if(!rt)return 0; 38 if(val[rt]==x)return rt; 39 if(val[rt]>x){ 40 int f=find_da(Ls(rt),x); 41 return f?f:rt; 42 } 43 return find_da(Rs(rt),x); 44 } 45 void rotate(int &k,int x){ 46 int y=fa[x],z=fa[y],fl=(Rs(y)==x),w=ch[x][!fl]; 47 if(y==k)k=x; 48 else ch[z][Rs(z)==y]=x; 49 ch[x][!fl]=y,ch[y][fl]=w; 50 if(w)fa[w]=y;fa[y]=x,fa[x]=z; 51 pushup(y),pushup(x); 52 return; 53 } 54 void splay(int &k,int x){ 55 while(x!=k){ 56 int y=fa[x]; 57 if(y!=k) 58 rotate(k,(Ls(fa[x])==x)^(Ls(fa[y])==y)?x:y); 59 rotate(k,x); 60 } 61 } 62 void insert(int id,int x,int v){ 63 int now=find_xi(Rt[id],x); 64 if(val[now]==x){ 65 splay(Rt[id],now),num[now]+=v,pushup(now); 66 return; 67 } 68 int nex=find_da(Rt[id],x); 69 splay(Rt[id],now),splay(Rs(now),nex); 70 cnt++,val[cnt]=x,num[cnt]=siz[cnt]=1; 71 fa[cnt]=nex,ch[nex][0]=cnt; 72 pushup(nex),pushup(now); 73 return; 74 } 75 #undef Ls 76 #undef Rs 77 }T; 78 int cnt,rot[N]; 79 struct seg{int ls,rs,v;}tr[N*250]; 80 #define Ls tr[rt].ls 81 #define Rs tr[rt].rs 82 LL query(int rt,int l,int r,int ql,int qr){ 83 if(!rt)return 0; 84 if(ql<=l&&qr>=r)return tr[rt].v; 85 int mid=(l+r)>>1;LL res=0; 86 if(ql<=mid)res=query(Ls,l,mid,ql,qr); 87 if(qr>mid)res+=query(Rs,mid+1,r,ql,qr); 88 return res; 89 } 90 void insert(int &rt,int l,int r,int k,int v){ 91 if(!rt)rt=++cnt;tr[rt].v+=v; 92 if(l==r)return; 93 int mid=(l+r)>>1; 94 if(k<=mid)insert(Ls,l,mid,k,v); 95 else insert(Rs,mid+1,r,k,v); 96 return; 97 } 98 LL ask(int l,int r,int ql,int qr){ 99 if(ql>qr||l>r)return 0; 100 LL ans=0; 101 for(;r;r-=r&-r)ans+=query(rot[r],1,INF,ql,qr); 102 for(;l;l-=l&-l)ans-=query(rot[l],1,INF,ql,qr); 103 return ans; 104 } 105 void add(int k,int x,int f){for(;k<=n;k+=k&-k)insert(rot[k],1,INF,x,f);} 106 int main(){ 107 n=R(),q=R(),Rt[n]=T.init(); 108 for(int i=1;i<=n;i++) 109 a[i]=R()+1,T.insert(n,a[i],1); 110 s.insert(n),li[n]=1; 111 for(int i=1;i<=n;i++){ 112 ans+=ask(0,i-1,a[i]+1,INF); 113 add(i,a[i],1);} 114 sum[n]=ans; 115 while(q--){ 116 int op=R(),x=(LL)R()^las,y,l,r; 117 it=s.lower_bound(x); 118 r=(*it),l=li[r],ans^=sum[r]; 119 if(!op){ 120 y=(LL)(R()^las)+1; 121 sum[r]-=ask(l-1,x-1,a[x]+1,INF)+ask(x,r,1,a[x]-1); 122 T.insert(r,a[x],-1),T.insert(r,y,1); 123 add(x,a[x],-1),add(x,a[x]=y,1); 124 sum[r]+=ask(l-1,x-1,a[x]+1,INF)+ask(x,r,1,a[x]-1); 125 ans^=sum[r]; 126 } 127 if(op){ 128 li[r]=x+1,T.insert(r,a[x],-1); 129 s.insert(x-1),li[x-1]=l,sum[x-1]=0; 130 LL num=(LL)ask(l-1,x-1,a[x]+1,INF)+ask(x,r,1,a[x]-1); 131 if(x-l<r-x){ 132 if(l!=x)Rt[x-1]=T.init(); 133 for(int i=l;i<x;i++){ 134 T.insert(r,a[i],-1); 135 int k=T.find_da(Rt[r],a[i]); 136 T.splay(Rt[r],k),num+=T.siz[T.ch[k][0]]; 137 T.insert(x-1,a[i],1); 138 k=T.find_da(Rt[x-1],a[i]); 139 T.splay(Rt[x-1],k); 140 sum[x-1]+=T.siz[T.ch[k][1]]; 141 } 142 sum[r]-=num,ans^=sum[x-1]^sum[r]; 143 } 144 else{ 145 swap(sum[r],sum[x-1]),swap(Rt[r],Rt[x-1]); 146 Rt[r]=T.init(),sum[r]=0; 147 for(int i=r;i>x;i--){ 148 T.insert(x-1,a[i],-1); 149 int k=T.find_da(Rt[x-1],a[i]); 150 T.splay(Rt[x-1],k),num+=T.siz[T.ch[k][1]]; 151 T.insert(r,a[i],1); 152 k=T.find_da(Rt[r],a[i]); 153 T.splay(Rt[r],k); 154 sum[r]+=T.siz[T.ch[k][0]]; 155 } 156 sum[x-1]-=num,ans^=sum[x-1]^sum[r]; 157 } 158 } 159 printf("%lld\n",las=ans); 160 } 161 return 0; 162 }