bzoj3376/poj1988[Usaco2004 Open]Cube Stacking 方塊遊戲 — 帶權並查集

題目鏈接:http://www.lydsy.com/JudgeOnline/problem.php?id=3376

題目大意:

編號爲1到n的n(1≤n≤30000)個方塊正放在地上.每個構成一個立方柱.

有P(1≤P≤100000)個指令.指令有兩種:

1.移動(M):將包含X的立方柱移動到包含Y的立方柱上.

2.統計(C):統計名含X的立方柱中,在X下方的方塊數目.

題解:

帶權並查集

存三個東西,x所在立方柱的最頂端fa[x],x所在立方柱的最底端d[x],x上面有多少個立方柱f[x](下面的圖畫錯了不包含x qwq..畫的時候一點感覺都沒有)。


那麼要求的x下方的數目就可以用f[d[x]]-f[x]來表示。

/*
	題意:
	n塊積木,m個操作或詢問。每次移動積木的時候,約翰會選擇兩塊積木X,Y,把X搬到Y的上方。如果X已經和其它積
	木疊在一起了,那麼應將這疊積木整體移動到Y的上方;如果Y已經和其它積木疊在一起了的,假設在Y上方最高處的
	積木爲Z,那麼應將X所在的那疊積木移動到Z的上方。每次詢問當前時刻,某一塊積木的下方有多少塊積木。
	n,m<=10^5
    輸入第一行 一個整數m,接下來m行,每行命令的格式爲: 操作  x  y  ( M 爲合併操作,C爲查詢 )

	題解:
	帶權並查集。
	對於每個點x,維護當前所在並查集(也就是這一堆積木中)最下方的積木low[x],最上方的積木fa[x],
	x到最上方積木的距離dist[x],則下方的積木數=dist[low[x]]-dist[x]。
	帶權並查集其實就是在Findfa的時候順便維護一些權值。
*/
#include<cstdio>
#include<cstring>

const int maxn=30000;
int fa[maxn],low[maxn],dist[maxn],N,M;

int Findfa(int x)
{
	if(fa[x]!=x)
	{
		int y=fa[x];
		fa[x]=Findfa(fa[x]);
		low[x]=low[y];
		dist[x]=dist[x]+dist[y];  // x上方木塊數=原x積木堆上方的木塊數 + Findfa更新後原積木堆x祖先y上方木塊數
	}
	return fa[x];
}

int main()
{
	for(int i=1;i<=maxn;++i) fa[i]=i,low[i]=i,dist[i]=0;  // 並查集初始化
	scanf("%d",&M);
	char op[5];
	int x,y;
	while(M>0)
	{
		M--;
		scanf("%s",&op);
		if(op[0]=='M')      //把 x放到y上
		{
			scanf("%d%d",&x,&y);
			int fx=Findfa(x),fy=Findfa(y);
			fa[fy]=fx;
			dist[fy]=dist[low[fx]]+1;
			low[fx]=low[fy];
			Findfa(fy);      // 並查集路徑壓縮,更新之前積木堆y中的積木最上方的積木編號
		}
		else
		{
			scanf("%d",&x);
			int t=Findfa(x);  
			int d=low[t];
			Findfa(d);   // 路徑壓縮,更新
			printf("%d\n",dist[d]-dist[x]);
		}
	}
	return 0;
}


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