白白的(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 }
View Code

猜你喜欢

转载自www.cnblogs.com/chmwt/p/10660968.html