P3302 [SDOI2013]森林

题目描述

一道非常平常的主席树题,其实还是蛮经典的

给出一个森林,满足两种操作

  • 求一条路径上的第 (k) 大值

  • 链接两个树

强制在线

P3302 [SDOI2013]森林

问题解决

看到第 (k) 小,自然而然就想到了主席树,但是要求不断连边,所以考虑 (LCT) 但是时间复杂度和代码度都不允许,区间第 (k) 小好像没什么思虑去优化,所以考虑来优化连边, (n) 颗树的连边貌似只有启发式合并了,但是这里要去思考如何维护主席树上的值,而且要满足时间复杂度

启发式合并的时候,我们把小的合并到大的上面去,合并的时候,我们要暴力把要修改的节点的父节点来修改这个节点,然后更新对应的 (st)

查询的时候我们有一点书上差分的感觉,因为主席树本质上和差分有点像,在树上建主席树,记录下(x,y,lca(x,y),fa(lca(x,y))) 的值,查询的时候遵循树上差分的想法,来查询就好了

总时间复杂度是 (O(nlog^2n)),但还是要卡一下时间

代码实现

#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn=8e4+5,maxe=4*maxn;
int lnk[maxn],son[maxe],nxt[maxe],cnt,tot;
int T,n,m,q;
int a[maxn],Fa[maxn],Son[maxn],hed[maxn];
inline void add_e(int x,int y){
	son[++tot]=y;nxt[tot]=lnk[x];lnk[x]=tot;
}
struct node{
	int size,ls,rs;
}t[maxn*600];
int root[maxn];
struct IO{
    static const int S=1<<21;
    char buf[S],*p1,*p2;int st[105],Top;
    ~IO(){clear();}
    inline void clear(){fwrite(buf,1,Top,stdout);Top=0;}
    inline void pc(const char c){Top==S&&(clear(),0);buf[Top++]=c;}
    inline char gc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
    inline IO&operator >> (char&x){while(x=gc(),x==' '||x=='
'||x=='r');return *this;}
    template<typename T>inline IO&operator >> (T&x){
        x=0;bool f=0;char ch=gc();
        while(ch<'0'||ch>'9'){if(ch=='-') f^=1;ch=gc();}
        while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=gc();
        f?x=-x:0;return *this;
    }
    inline IO&operator << (const char c){pc(c);return *this;}
    template<typename T>inline IO&operator << (T x){
        if(x<0) pc('-'),x=-x;
        do{st[++st[0]]=x%10,x/=10;}while(x);
        while(st[0]) pc('0'+st[st[0]--]);return *this;
    }
}fin,fout;
inline int read(){
    int x=0;char ch=' ';int f=1;
    while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    if(ch=='-')f=-1,ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*f;
}
void build(int &now,int l,int r){
	now=++cnt;t[now].size=0;
	if(l==r)return ;
	int mid=(r-l>>1)+l;
	build(t[now].ls,l,mid);
	build(t[now].rs,mid+1,r);
}
void insert(int &now,int pre,int l,int r,int x){
	now=++cnt;t[now]=t[pre];t[now].size++;
	if(l==r)return ;
	int mid=(r-l>>1)+l;
	if(x<=mid)insert(t[now].ls,t[pre].ls,l,mid,x);
	else insert(t[now].rs,t[pre].rs,mid+1,r,x);
}
int b[maxn],size;
int query(int x,int y,int pre1,int pre2,int l,int r,int k){
	if(l==r)return b[l];
	int lsize=t[t[x].ls].size+t[t[y].ls].size-t[t[pre1].ls].size-t[t[pre2].ls].size;
	int mid=(r-l>>1)+l;
	if(k<=lsize)return query(t[x].ls,t[y].ls,t[pre1].ls,t[pre2].ls,l,mid,k);
	else return query(t[x].rs,t[y].rs,t[pre1].rs,t[pre2].rs,mid+1,r,k-lsize);
}
inline int Hash(int x){
	return lower_bound(b+1,b+1+size,x)-b;
}
int find(int x){
	return Fa[x]==x?x:Fa[x]=find(Fa[x]);
}
int st[maxn][17],dep[maxn],vis[maxn];
void dfs(int x,int father,int rt){
	st[x][0]=father;
	for(int k=1;k<=16;k++){
		st[x][k]=st[st[x][k-1]][k-1];
	}
	Son[rt]++;dep[x]=dep[father]+1;Fa[x]=father;vis[x]=1;
	insert(root[x],root[father],1,size,Hash(a[x]));
	for(int j=lnk[x];j;j=nxt[j]){
		if(son[j]==father)continue;
		dfs(son[j],x,rt);
	}
}
inline int Lca(int x,int y){
	if(x==y)return x;
	if(dep[x]>dep[y])swap(x,y);
	for(int k=16;k>=0;k--){
		if(dep[st[y][k]]>=dep[x])y=st[y][k];
	}
	if(x==y)return x;
	for(int k=16;k>=0;k--)
		if(st[x][k]!=st[y][k])x=st[x][k],y=st[y][k];
	return st[x][0];
}
int main(){
	freopen("P3302.in","r",stdin);
	freopen("P3302.out","w",stdout);
	T=read();T=1;
	while(T--){
		memset(lnk,0,sizeof lnk);
		memset(dep,0,sizeof dep);
		memset(vis,0,sizeof vis);
		memset(st,0,sizeof st);
		memset(Son,0,sizeof Son);
		tot=0;cnt=0;n=read();m=read();q=read();
		for(int i=1;i<=n;i++)a[i]=read(),b[i]=a[i],Fa[i]=i;
		sort(b+1,b+1+n);
		size=unique(b+1,b+1+n)-b-1;
		for(int i=1;i<=m;i++){
			int x=read(),y=read();
			add_e(x,y);add_e(y,x);
		}
		build(root[0],1,size);
		for(int i=1;i<=n;i++){
			if(!vis[i]){dfs(i,0,i);Fa[i]=i;}
		}
		int lastans=0;
		for(int i=1;i<=q;i++){
			char ch[3];
			int x,y,k;
			scanf("%s",ch);
			x=read()^lastans;
			y=read()^lastans;
			if(ch[0]=='Q'){
				k=read()^lastans;
				int lca=Lca(x,y);
				lastans=query(root[x],root[y],root[lca],root[st[lca][0]],1,size,k);
				printf("%d
",lastans);
			}
			else {
				add_e(x,y);add_e(y,x);
				int fx=find(x),fy=find(y);
				if(son[fx]<son[fy]){
					swap(fx,fy);swap(x,y);
				}
				dfs(y,x,fx);
			}
		}
	}
	return 0;
}
原文地址:https://www.cnblogs.com/martian148/p/15261812.html