码迷,mamicode.com
首页 > 其他好文 > 详细

P3302 [SDOI2013]森林

时间:2021-04-13 12:22:35      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:sdi   pen   class   启发式   nlog   swap   main   http   alt   

P3302 [SDOI2013]森林

P3302 [SDOI2013]森林

这道题加强版,多了连边的操作,强制在线。

技术图片

考虑在那题的基础上怎么做这个题。

于是我们现在只需要解决操作2,我们发现其实我们维护的本质就是一棵棵主席树,而且这些主席树大小的总量一定。

再加上这道题没有删边,于是我们可以考虑启发式合并。(ps:没有删边操作可以考虑启发式合并,有如果不强制在线可以考虑线段树分治,如果强制在线,那么可以考虑有没有性质或者LCT。)

那么这样就很简单了,对于操作2我们直接重构整棵树即可。

同时,这里我们必须使用可以在线的倍增LCA来维护LCA。

时间复杂度\(O(nlog^2n)\)

代码:

#include<bits/stdc++.h>
using namespace std;
template <typename T>
inline void read(T &x){
	x=0;char ch=getchar();bool f=false;
	while(!isdigit(ch)){if(ch==‘-‘){f=true;}ch=getchar();}
	while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	x=f?-x:x;
	return ;
}
template <typename T>
inline void write(T x){
	if(x<0) putchar(‘-‘),x=-x;
	if(x>9) write(x/10);
	putchar(x%10^48);
	return ;
}
const int N=4e5+5,NN=1e8;
int n,m,q,a[N],root[N],cur,Idx,b[N];
int nex[N<<1],to[N<<1],head[N],idx;
int fa[N][18],dep[N],Fa[N],siz[N];
inline int Getfa(int x){return x==Fa[x]?x:Fa[x]=Getfa(Fa[x]);}
inline void add(int u,int v){
	nex[++idx]=head[u];
	to[idx]=v;
	head[u]=idx;
	return ;
}
struct SGTree{
	int lc,rc,val,sum;
	#define lc(x) t[x].lc
	#define rc(x) t[x].rc
	#define val(x) t[x].val
	#define sum(x) t[x].sum
}t[NN];
inline void Pushup(int x){sum(x)=sum(lc(x))+sum(rc(x));return ;}
void Modify(int &x,int pre,int l,int r,int pos,int v){
	x=++cur;
	t[x]=t[pre];sum(x)++;
	if(l==r) return ;
	int mid=(l+r)>>1;
	if(pos<=mid) Modify(lc(x),lc(pre),l,mid,pos,v);
	else Modify(rc(x),rc(pre),mid+1,r,pos,v);
	return ;
}
inline void Update(int x,int f){
	fa[x][0]=f;dep[x]=dep[f]+1;
	for(int i=1;i<=16;i++) fa[x][i]=fa[fa[x][i-1]][i-1];
	Modify(root[x],root[f],1,Idx,a[x],1);
	return ;
}
int QueryLca(int u,int v){
	if(dep[u]<dep[v]) swap(u,v);
	for(int i=16;i>=0;i--) if(dep[fa[u][i]]>=dep[v]) u=fa[u][i];
	if(u==v) return u;
	for(int i=16;i>=0;i--) if(fa[u][i]!=fa[v][i]) u=fa[u][i],v=fa[v][i];
	return fa[u][0];
}
int QueryKth(int u,int v,int lca,int falca,int l,int r,int k){
	if(l==r) return l;
	int mid=(l+r)>>1,lsum=sum(lc(u))+sum(lc(v))-sum(lc(lca))-sum(lc(falca));
	if(k<=lsum) return QueryKth(lc(u),lc(v),lc(lca),lc(falca),l,mid,k);
	else return QueryKth(rc(u),rc(v),rc(lca),rc(falca),mid+1,r,k-lsum);
}
void Build(int x,int f){
	Update(x,f);
	for(int i=head[x];i;i=nex[i]){
		int y=to[i];
		if(y==f) continue;
		Build(y,x);
	}
	return ;
}
void Link(int u,int v){
	int x=Getfa(u),y=Getfa(v);
	if(siz[x]<siz[y]) swap(u,v),swap(x,y);
	siz[x]+=siz[y],Fa[y]=x;
	add(u,v),add(v,u);
	Build(v,u);
	return ;
}
bool vis[N];
void dfs(int x,int f){
	vis[x]=true;Update(x,f);
	for(int i=head[x];i;i=nex[i]){
		int y=to[i];
		if(y==f) continue;
		dfs(y,x);
	}
	return ;
}
int main(){
	int test;read(test);
	read(n),read(m),read(q);
	for(int i=1;i<=n;i++) read(a[i]),Fa[i]=i,siz[i]=1,b[i]=a[i];
	sort(b+1,b+n+1);Idx=unique(b+1,b+n+1)-b-1;
	for(int i=1;i<=n;i++) a[i]=lower_bound(b+1,b+Idx+1,a[i])-b,Modify(root[i],0,1,Idx,a[i],1);
	for(int i=1;i<=m;i++){
		int u,v;
		read(u),read(v);
		add(u,v);add(v,u);
	}
	for(int i=1;i<=n;i++) if(!vis[i]) dfs(i,0);
	int las=0;
	for(int i=1;i<=q;i++){
		char op[5];int u,v,w;
		scanf("%s",op);
		if(op[0]==‘Q‘){
			read(u),read(v),read(w);
			u^=las,v^=las,w^=las;int LCA=QueryLca(u,v);
			las=b[QueryKth(root[u],root[v],root[LCA],root[fa[LCA][0]],1,Idx,w)];
			write(las),putchar(‘\n‘);
		}
		else{
			read(u),read(v);
			u^=las,v^=las;
			Link(u,v);
		}
	}
	return 0;
}

P3302 [SDOI2013]森林

标签:sdi   pen   class   启发式   nlog   swap   main   http   alt   

原文地址:https://www.cnblogs.com/Akmaey/p/14649693.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!