克魯斯卡爾重構樹

前言

水的時候看到的算法

正文

對於一些問題,比如什麼在一幅圖從一個點開始經過的邊小於等於某個值所能達到的點集中求balabala
首先搞出最小生成樹(顯然只有最小生成樹上的邊有用)
然後從小到大枚舉邊,把邊所連的兩個點合併成一個新的點(新的點的權值等於邊的權值),新的點繼承原來兩個點相連的邊
將所有點合併完後,我們開始建克魯斯卡爾重構樹,這棵樹的點就是原圖中的點加上新建的點,這棵樹的邊是每個新建的點向合併的兩個點的連邊
這樣就會有很好的性質,在一個節點子樹內的所有葉子所代表的點在原圖中互相達到經過的邊小於等於這個節點的權值
然後就可以用各種算法來操作一波了

例題

[bzoj3551][ONTAK2010]Peaks加強版
本題其實大概是裸題了吧
直接克魯斯卡爾重構樹+主席樹就好了
代碼

#include<cstdio>
#include<cctype>
#include<algorithm>
namespace fast_IO
{
	const int IN_LEN=1000000,OUT_LEN=1000000;
	char ibuf[IN_LEN],obuf[OUT_LEN],*ih=ibuf+IN_LEN,*oh=obuf,*lastin=ibuf+IN_LEN,*lastout=obuf+OUT_LEN-1;
	inline char getchar_(){return (ih==lastin)&&(lastin=(ih=ibuf)+fread(ibuf,1,IN_LEN,stdin),ih==lastin)?EOF:*ih++;}
	inline void putchar_(const char x){if(oh==lastout)fwrite(obuf,1,oh-obuf,stdout),oh=obuf;*oh++=x;}
	inline void flush(){fwrite(obuf,1,oh-obuf,stdout);}
}
using namespace fast_IO;
#define getchar() getchar_()
#define putchar(x) putchar_((x))
#define rg register
typedef long long ll;
template <typename T> inline T max(const T a,const T b){return a>b?a:b;}
template <typename T> inline T min(const T a,const T b){return a<b?a:b;}
template <typename T> inline void mind(T&a,const T b){a=a<b?a:b;}
template <typename T> inline void maxd(T&a,const T b){a=a>b?a:b;}
template <typename T> inline T abs(const T a){return a>0?a:-a;}
template <typename T> inline void Swap(T&a,T&b){T c=a;a=b;b=c;}
template <typename T> inline T gcd(const T a,const T b){if(!b)return a;return gcd(b,a%b);}
template <typename T> inline T lcm(const T a,const T b){return a/gcd(a,b)*b;}
template <typename T> inline T square(const T x){return x*x;};
template <typename T> inline void read(T&x)
{
	char cu=getchar();x=0;bool fla=0;
	while(!isdigit(cu)){if(cu=='-')fla=1;cu=getchar();}
	while(isdigit(cu))x=x*10+cu-'0',cu=getchar();
	if(fla)x=-x;
}
template <typename T> inline void printe(const T x)
{
	if(x>=10)printe(x/10);
	putchar(x%10+'0');
}
template <typename T> inline void print(const T x)
{
	if(x<0)putchar('-'),printe(-x);
	else printe(x);
}
const int maxn=200005,maxm=500005;
int n,m,q,h[maxn],lsh[maxn],lshn;
struct edge
{
	int u,v,w;
	bool operator <(const edge&b)const
	{
		return w<b.w;
	}
}Q[maxm];
int bcj[maxn],node;
int fa[maxn][21],val[maxn];
void newnode()
{
	node++;
	bcj[node]=node;
	fa[node][0]=node;
}
int find(const int x)
{
	if(x==bcj[x])return x;
	return bcj[x]=find(bcj[x]);
}
int son[maxn][2];
int tid[maxn],tim,endd[maxn],bak[maxn];
int SZ[maxn];
void dfs(const int u)
{
	tid[u]=++tim,bak[tim]=u;
	if(son[u][0])dfs(son[u][0]),dfs(son[u][1]);
	endd[u]=tim;
}
struct nd
{
	nd *lson,*rson;
	int size;
}*root[maxn],empty,*Null,P[maxn*20];
int usd;
inline nd*newnd()
{
	usd++;
	nd*r=&P[usd];
	r->lson=r->rson=Null,r->size=0;
	return r;
}
nd*insert(nd*dq,nd*las,const int l,const int r,const int v)
{
	if(l!=r)
	{
		const int mid=(l+r)>>1;
		if(v<=mid)
		{
			dq->rson=las->rson;
			dq->lson=insert(newnd(),las->lson,l,mid,v);
		}
		else
		{
			dq->lson=las->lson;
			dq->rson=insert(newnd(),las->rson,mid+1,r,v);
		}
	}
	dq->size=las->size+1;
	return dq;
}
int kth(nd*dq,nd*las,const int l,const int r,const int k)
{
	if(l==r)return l;
	const int v=dq->rson->size-las->rson->size,mid=(l+r)>>1;
	if(v<k)return kth(dq->lson,las->lson,l,mid,k-v);
	return kth(dq->rson,las->rson,mid+1,r,k);
}
int bz(int v,const int x)
{
	for(rg int i=20;i>=0;i--)
		if(val[fa[v][i]]<=x)
			v=fa[v][i];
	return v;
}
int main()
{
	empty.lson=empty.rson=Null=&empty;
	read(n),read(m),read(q);
	for(rg int i=1;i<=n;i++)read(h[i]),newnode(),lsh[i]=h[i],SZ[i]=1;
	std::sort(lsh+1,lsh+n+1);
	lshn=std::unique(lsh+1,lsh+n+1)-lsh-1;
	for(rg int i=1;i<=n;i++)h[i]=std::lower_bound(lsh+1,lsh+lshn+1,h[i])-lsh;
	for(rg int i=1;i<=m;i++)read(Q[i].u),read(Q[i].v),read(Q[i].w);
	std::sort(Q+1,Q+m+1);
	for(rg int i=1;i<=m;i++)
	{
		const int u=Q[i].u,v=Q[i].v,U=find(u),V=find(v);
		if(U==V)continue;
		newnode();
		fa[U][0]=fa[V][0]=node;
		val[node]=Q[i].w;
		bcj[U]=bcj[V]=node;
		son[node][0]=U,son[node][1]=V;
		SZ[node]=SZ[U]+SZ[V];
	}
	for(rg int i=1;i<=20;i++)
		for(rg int j=1;j<=node;j++)
			fa[j][i]=fa[fa[j][i-1]][i-1];
	for(rg int i=1;i<=node;i++)if(fa[i][0]==i)dfs(i);
	root[0]=newnd();
	for(rg int i=1;i<=tim;i++)root[i]=insert(newnd(),root[i-1],0,lshn,h[bak[i]]);
	int lastans=0;
	while(q--)
	{
		int v,x,k;
		read(v),read(x),read(k);
		v^=lastans,x^=lastans,k^=lastans;
		const int T=bz(v,x);
		if(SZ[T]<k)
		{
			print(-1),putchar('\n');
			lastans=0;
			continue;
		}
		lastans=lsh[kth(root[endd[T]],root[tid[T]-1],0,lshn,k)];
		print(lastans),putchar('\n');
	}
	return flush(),0;
}

總結

應用有侷限性,但是思路還是很不錯的

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章