DTOJ #4139. 白白的(baibaide)

题意

给一个长度为 n ( n ≤ 1.5 × 1 0 5 ) n(n \leq 1.5 \times 10^5) n(n1.5×105) 的序列,每个点有权值 a i a_i ai,初始均为白色。
需要支持 q ( q ≤ 2 × 1 0 4 ) q(q \leq 2 \times 10^4) q(q2×104) 次以下两种操作:
1. 1. 1. a x a_x ax 修改为 y y y
2. 2. 2. x x x 位置染黑。

定义一个连续白色段的权值为其中逆序对的个数,你需要在每次操作后输出所有白色连续的的权值的异或和。强制在线。

题解

小清新数据结构。

显然每次操作时,先把所在连续白色连续段的权值扣掉,算出新的权值再异或回去。

显然我们可以用 s e t set set p a i r pair pair 来维护所在的连续段。

先考虑 1 1 1 操作,其实就是扣去 a x a_x ax 在其所在段中的逆序对个数,再加上 y y y 在该段中的逆序对个数。这里可以用树套树维护(树套 s p l a y splay splay 不知道为什么过不去,就改成树套树了)。

再考虑 2 2 2 操作,不难发现,我们无法求出一段和一段之间的逆序对个数,所以我们就要考虑一个对一段的逆序对个数。不过直接做显然效率会退化到 O ( n 2 ) O(n^2) O(n2),所以我们仔细考虑一下,这里只有分裂,没有合并,注意到他的有效空间不会太大,所以想到类似启发式合并的方法,也就是启发式分裂。
每次我们把分裂的两段区间中小的那个区间里的点拿出来,扣掉和大的区间之间的逆序对个数,然后在暴力 O ( l e n m i n l o g l e n m i n ) O(len_{min} log_{len_{min}}) O(lenminloglenmin) 把新区间的逆序对算出来就好。至于怎么求出一个点和一块的逆序对数量,拿个随便什么东西维护一下就好了。这里建议用 s p l a y splay splay ,因为你前面已经有一个 n l o g 2 n nlog^2n nlog2n 的空间了,再多一个可能会开不下,而 s p l a y splay splay 的优点就在于方便以及节约空间。然后你就可以愉快地切掉这道题了~~~~

代码

#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int N=150005;
const int MAXN=1e9;
inline int read(){
	int k=0,f=1;char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9')k=k*10+c-'0',c=getchar();
	return k*f;
}
int ch[N<<6][2],fa[N<<6],val[N<<6],now,cnt[N<<6],rt[N<<6],sz[N<<6],n,q,nw,be[N],a[N];
LL shu[N<<6],ans,lastans,tim;
int root[N],t;
struct Node{
	int lc,rc,sum;
}T[N*400];
set<pair<int,int> > qu;
inline int get(int x){
	return ch[fa[x]][1]==x;
}
inline void update(int x){
	sz[x]=cnt[x];
	if(ch[x][0])sz[x]+=sz[ch[x][0]];
	if(ch[x][1])sz[x]+=sz[ch[x][1]];
}
inline void rotate(int x){
	int F=fa[x],k=get(x),G=ch[x][k^1];
	if(fa[F])ch[fa[F]][get(F)]=x;
	fa[x]=fa[F];fa[F]=x;fa[G]=F;
	ch[x][k^1]=F;ch[F][k]=G;
	update(F);update(x);
}
inline void splay(int x,int &p){
	while(fa[x]){
		if(fa[fa[x]])rotate((get(x)==get(fa[x]))?fa[x]:x);
		rotate(x);
	}
	p=x;
}
inline void insert(int &p,int x){
	if(!p){
		p=++now;
		cnt[p]=1;val[p]=x;
		return;
	}
	int k=p;
	while(1){
		if(val[k]==x){
			cnt[k]++,splay(k,p);
			return;
		}
		if(!ch[k][x>val[k]]){
			now++;
			cnt[now]=1;val[now]=x;
			ch[k][x>val[k]]=now;fa[now]=k;
			splay(now,p);
			return;
		}
		k=ch[k][x>val[k]];
	}
}
inline int find(int x,int &p){
	if(!p)return 0;
	int s=0,k=p;
	while(1){
//		tim++;
		if(!k)return s;
		//cout<<"FIND "<<val[k]<<" "<<x<<" "<<cnt[k]<<" "<<ch[k][1]<<" "<<val[ch[k][1]]<<" "<<cnt[ch[k][1]]<<endl;
		if(x>val[k])k=ch[k][1];
		else{
			s+=(x<=val[k])?sz[ch[k][1]]:0;
			if(val[k]==x){
				splay(k,p);
				return s;
				}
			s+=cnt[k];
			k=ch[k][0];
		}
	}
	return 0;
}
inline int find_f(int x,int &p){
	if(!p)return 0;
	int s=0,k=p;
	while(1){
//		tim++;
		if(!k)return s;
	//	cout<<"find_F "<<x<<" "<<val[k]<<" "<<val[ch[k][0]]<<" "<<sz[ch[k][0]]<<endl;
		if(x<val[k])k=ch[k][0];
		else{
			s+=(x>=val[k])?sz[ch[k][0]]:0;
			if(val[k]==x){
				splay(k,p);
				return s;
			}
			s+=cnt[k];
			k=ch[k][1];
		}
	}
	return 0;
}
inline int find_id(int x,int &p){
	if(!p)return 0;
	int k=p;
	while(1){
		if(val[k]==x){
			splay(k,p);
			return k;
		}
		k=ch[k][x>val[k]];
	}
	return 0;
}
inline int pre(int p){
	p=ch[p][0];
	while(ch[p][1])p=ch[p][1];
	return p;
}
inline void del(int x,int &p){
	int k=find_id(x,p);
	if(cnt[k]>1){cnt[k]--;return;}
	if(!ch[k][0]&&!ch[k][1]){p=0;return;}
	if(!ch[k][0]||!ch[k][1]){
		int kp=ch[k][0]|ch[k][1];
		fa[kp]=0;p=kp;
		return;
	}
	int kp=pre(k);splay(kp,p);
//	cout<<"DEl "<<val[kp]<<" "<<val[k]<<endl;
	fa[ch[k][1]]=kp;ch[kp][1]=ch[k][1];p=kp;
	update(p);
}
inline int lowbit(int x){return x&(-x);}
void add(int &p,int l,int r,int x,int d){
	if(!p)p=++t;
	T[p].sum+=d;
	if(l==r)return;
	int mid=(l+r)>>1;
	if(x<=mid)add(T[p].lc,l,mid,x,d);
	else add(T[p].rc,mid+1,r,x,d);
}
int query(int p,int l,int r,int L,int R){
	if(!p)return 0;
	if(l>=L&&r<=R)return T[p].sum;
	int mid=(l+r)>>1,s=0;
	if(L<=mid)s+=query(T[p].lc,l,mid,L,R);
	if(R>mid)s+=query(T[p].rc,mid+1,r,L,R);
	return s;
}
inline int ask(int l,int r,int L,int R){
	if(L>R||l>r)return 0;
	if(R<=0||L<=0)return 0;
	int s=0;l--;
	for(;r;r-=lowbit(r))s+=query(root[r],1,MAXN,L,R);
	for(;l;l-=lowbit(l))s-=query(root[l],1,MAXN,L,R);
	return s;
}
inline void solve_1(int x,int y){
	auto lt=qu.upper_bound(make_pair(x,n+1));
	if(lt==qu.begin())return;
	--lt;
	if(x>(*lt).second)return;
	int l=(*lt).first,r=(*lt).second;
	ans^=shu[be[l]];
//	cout<<"FAQ "<<shu[be[l]];
	for(int j=x;j<=n;j+=lowbit(j))add(root[j],1,MAXN,a[x],-1);
	if(x!=l){
		shu[be[l]]+=ask(l,x-1,y+1,MAXN)-ask(l,x-1,a[x]+1,MAXN);
	//	cout<<"ask l "<<ask(l,x-1,y+1,MAXN)<<" "<<ask(l,x-1,a[x]+1,MAXN)<<endl;
	}
	if(x!=r){
		shu[be[l]]+=ask(x+1,r,1,y-1)-ask(x+1,r,1,a[x]-1);
	//	cout<<"ask r "<<ask(x+1,r,1,y-1)<<" "<<ask(x+1,r,1,a[x]-1)<<endl;
	}
//	cout<<"faq "<<shu[be[l]]<<endl;
	for(int j=x;j<=n;j+=lowbit(j))add(root[j],1,MAXN,y,1);
	del(a[x],rt[be[l]]);
	insert(rt[be[l]],y);
	a[x]=y;
	ans^=shu[be[l]];
	lastans=ans;
}
inline void solve_2(int x){
//	cout<<"Solve_2 "<<x<<endl;
//	for(auto it=qu.begin();it!=qu.end();++it)cout<<"Qu "<<(*it).first<<" "<<(*it).second<<endl;
	auto lt=qu.upper_bound(make_pair(x,n+1));
	--lt;
	int l=(*lt).first,r=(*lt).second;
	ans^=shu[be[l]];
//	cout<<"FAQ "<<ans<<" "<<l<<" "<<r<<" "<<x<<endl;
	if(l==r){
		qu.erase(make_pair(l,r));
		lastans=ans;
		return;
	}
	if(x==l){
		qu.erase(make_pair(l,r));
		qu.insert(make_pair(l+1,r));
		be[l+1]=be[l];be[l]=0;
		shu[be[l+1]]-=find_f(a[x],rt[be[l+1]]);
//		cout<<"Cha_f "<<a[x]<<" "<<cha_f(a[x],rt[be[l+1]])<<endl;
		del(a[x],rt[be[l+1]]);
		ans^=shu[be[l+1]];
		lastans=ans;
		return;
	}
	if(x==r){
		qu.erase(make_pair(l,r));
		qu.insert(make_pair(l,r-1));
		shu[be[l]]-=find(a[x],rt[be[l]]);
		del(a[x],rt[be[l]]);
		ans^=shu[be[l]];
		lastans=ans;
		return;
	}
	int L1=l,R1=x-1,L2=x+1,R2=r,len1=(R1-L1+1),len2=(R2-L2+1);
//	cout<<"FAQ "<<L1<<" "<<R1<<" "<<L2<<" "<<R2<<" "<<shu[be[L1]]<<endl;
	qu.erase(make_pair(l,r));
	qu.insert(make_pair(L1,R1));
	qu.insert(make_pair(L2,R2));
	if(len1<len2){
		be[L2]=be[L1];
		for(int i=L1;i<=x;++i){
			shu[be[L2]]-=find_f(a[i],rt[be[L2]]);
			del(a[i],rt[be[L2]]);
		}
		nw++;be[L1]=nw;
		for(int i=L1;i<=R1;++i){
			insert(rt[be[L1]],a[i]);
			shu[be[L1]]+=find(a[i],rt[be[L1]]);
		}
	}
	else{
		be[L2]=++nw;
		for(int i=R2;i>=x;--i){
			shu[be[L1]]-=find(a[i],rt[be[L1]]);
			del(a[i],rt[be[L1]]);
		}
		for(int i=L2;i<=R2;++i){
			insert(rt[be[L2]],a[i]);
			shu[be[L2]]+=find(a[i],rt[be[L2]]);
		}
	}
//	cout<<"FAQ "<<shu[be[L1]]<<" "<<shu[be[L2]]<<endl;
	ans^=shu[be[L1]]^shu[be[L2]];
	lastans=ans;
}
int main(){
//	freopen("data.out","r",stdin);
//	freopen("baibaide.out","w",stdout);
	n=read();q=read();
	for(int i=1;i<=n;++i){
		a[i]=read();
		for(int j=i;j<=n;j+=lowbit(j))add(root[j],1,MAXN,a[i],1);
	}
//	printf("%lld\n",tim);
	nw=1;be[1]=nw;
	for(int i=1;i<=n;++i){
		insert(rt[nw],a[i]);
		shu[nw]+=find(a[i],rt[nw]);
	}
	ans=shu[nw];qu.insert(make_pair(1,n));
	while(q--){
		int op=read();
		LL x,y;
		if(!op){
			x=read(),y=read();
			x=x^lastans,y=y^lastans;
			solve_1(x,y);
		}
		else{
			x=read();x=x^lastans;
			solve_2(x);
		}
		printf("%lld\n",lastans);
	}
	//printf("%lld\n",tim);
	return 0;
}
/*
4 2
4 3 2 1
0 2 5
1 4
*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值