2022牛客多校 第8场 G Lexicographic Comparison(平衡树维护环/置换)

传送门
\(n\)个数的排列的置换会形成多个环,改变\(p_i\)会改变置换的环的情况,两个修改位置在同一个环里,环会分成两个。否则会合并两个环。

只需要知道这些环的情况。挨个检查每一个环的下标最靠前的位置上的数在\(x\)\(y\)轮的情况就行了。
由此可以知道\(a_i\)并不重要。

但是上面的思路中因为环的数量较多,对一个环的判断时间较长,无法解决问题。

可以发现只需要一个长度的所有环的下标最靠前位置上的数在\(x\)\(y\)轮的情况就行了,因为如果这个位置相等,其他同长度的环的所有位置一定相等,不相等的话就没有意义往后比较了。所以只需要最前面的位置上的数。

进一步可以发现,所有长度可以整除\(y-x\)的环的位置上的数在\(x\)\(y\)轮的情况必然完全相同,否则一定不相同。

所以就是比较所有长度不可以整除\(y-x\)的环的最靠前位置上的数在\(x\)\(y\)轮的情况。

对于每一类长度相同的环记录所有环中的最靠前位置。因为环的种类最多有\(\sqrt{n}\)种,每次询问,枚举所有长度的环,然后找出在\(x\)\(y\)轮不相等环上的最靠前位置,比较这个位置上的在\(x\)\(y\)轮的数就行了。

想到在每一个位置维护以这个位置为最靠前位置的环(有的位置可能为空)。这样就能快速找到对应的环,然后找到第\(x\)\(y\)轮的数。

用平衡树维护每个环,每个环以一个剪开后的序列的形式维护,然后环的合并和分离手玩一下就是序列的区间操作。

然后需要快速找到这个环中最小下标,在维护的序列中的位置,然后分别后推\(x-1\)\(y-1\)个位置就能知道对应的数了。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<set>
#include<ctime>
#include<cstdlib>
using namespace std;
#define int long long
const int N=1e5+100;

int read(){
	int sum=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){sum=sum*10+ch-'0';ch=getchar();}
	return sum*f;
}
set<int> st[N]; 
int tot,id[N],mn[N],fa[N],ch[N][2],rad[N],Size[N];
int new_node(int x){
	int now=++tot;
	id[now]=x;
	mn[now]=x;
	fa[now]=0;
	ch[now][0]=ch[now][1]=0;
	rad[now]=rand();
	Size[now]=1;
	return now;
}
void update(int now){
	mn[now]=id[now];
	Size[now]=1;
	if(ch[now][0])mn[now]=min(mn[now],mn[ch[now][0]]),Size[now]+=Size[ch[now][0]];
	if(ch[now][1])mn[now]=min(mn[now],mn[ch[now][1]]),Size[now]+=Size[ch[now][1]];
}
int merge(int x,int y){
	if(x==0||y==0)return x+y;
	if(rad[x]>rad[y]){
		ch[x][1]=merge(ch[x][1],y);
		update(x);
		fa[ch[x][1]]=x;
		return x;
	}
	else{
		ch[y][0]=merge(x,ch[y][0]);
		update(y);
		fa[ch[y][0]]=y;
		return y;
	}
}
void split(int now,int &x,int &y,int k){
	if(now==0){
		x=y=0;
		return;
	}
	if(Size[ch[now][0]]<k){
		x=now;
		fa[ch[now][1]]=0;
		split(ch[now][1],ch[x][1],y,k-Size[ch[now][0]]-1);
		if(ch[x][1])fa[ch[x][1]]=x;
		update(x);
	}
	else{
		y=now;
		fa[ch[now][0]]=0;
		split(ch[now][0],x,ch[y][0],k);
		if(ch[y][0])fa[ch[y][0]]=y;
		update(y);
	}
}
int get_root(int x){
	if(fa[x]==0)return x;
	else return get_root(fa[x]);
}
int get_rank(int x,int root){
	int ans=Size[ch[x][0]]+1;
	while(x!=root){
		if(ch[fa[x]][1]==x)ans+=Size[ch[fa[x]][0]]+1;
		x=fa[x];
	}
	return ans;
}
void st_del(int len,int first){
	st[len].erase(first);
	if(st[len].size()==0)st[0].erase(len);
}
void st_ins(int len,int first){
	if(st[len].size()==0)st[0].insert(len);
	st[len].insert(first);
}
void clear(int n){
	for(int i=0;i<=n;i++)st[i].clear();
	tot=0; 
}
int get_kth(int k,int now){
	int l=ch[now][0];
	if(Size[l]>=k)return get_kth(k,l);
	else if(Size[l]+1>=k)return now;
	else return get_kth(k-Size[l]-1,ch[now][1]); 
}
int root[N],a[N];
int X,Y,Z;
char s[100];
signed main(){
	srand(time(NULL));
	int T=read();
	while(T--){
		int n=read(),q=read();
		for(int i=1;i<=n;i++)a[i]=i,root[i]=new_node(i);
		st[0].insert(1);
		for(int i=1;i<=n;i++)st[1].insert(i);
		while(q--){
			scanf("%s",s+1);
			int x=read(),y=read();
			if(s[1]=='c'){
				x--,y--;
				if(x==y){
					printf("=\n");
					continue; 
				}
				bool rev=0;
				int pos=n+1,len;
				if(x>y)swap(x,y),rev=1;
				bool flag=0;
				for(auto i=st[0].begin();i!=st[0].end();i++){
					if((y-x)%*i==0)continue;
					flag=1;
					if(*st[*i].begin()<pos){
						pos=*st[*i].begin();
						len=*i;
					}
				}
				if(flag==0){
					printf("=\n");
					continue;
				}
				int rk=get_rank(mn[root[pos]],root[pos]);
				int w_x=a[get_kth((rk+x%len-1)%len+1,root[pos])];
				int w_y=a[get_kth((rk+y%len-1)%len+1,root[pos])];
				if((w_x<w_y)^rev)printf("<\n");
				else printf(">\n"); 
			}
			else{
				if(x==y)continue;
				if(s[6]=='a')swap(a[x],a[y]);
				else{
					int x_root=get_root(x);
					int y_root=get_root(y);
					int x_rk=get_rank(x,x_root);
					int y_rk=get_rank(y,y_root);
					if(x_root==y_root){
						st_del(Size[x_root],mn[x_root]);
						split(x_root,X,Z,max(x_rk,y_rk));
						split(X,X,Y,min(x_rk,y_rk));
						root[mn[Y]]=Y;
						st_ins(Size[root[mn[Y]]],mn[Y]);
						int Mn=n+1;
						if(X)Mn=min(Mn,mn[X]);
						if(Z)Mn=min(Mn,mn[Z]);
						root[Mn]=merge(X,Z);
						st_ins(Size[root[Mn]],Mn);
					}
					else{
						int Mn=min(mn[x_root],mn[y_root]);
						st_del(Size[x_root],mn[x_root]);
						st_del(Size[y_root],mn[y_root]);
						split(y_root,X,Y,y_rk);
						Y=merge(Y,X);
						split(x_root,X,Z,x_rk);
						root[Mn]=merge(merge(X,Y),Z);
						st_ins(Size[root[Mn]],Mn);
					}
				}
			}
		}
		clear(n);
	}
	return 0;
}
/*
1
6 7
swap_p 3 6
swap_p 3 5
swap_p 5 6
swap_p 4 2
swap_a 1 4
cmp 34 81
cmp 87 76

*/
posted @ 2022-08-28 19:44  Xu-daxia  阅读(39)  评论(0编辑  收藏  举报