【WC2006】水管局長

問題描述

SC省MY市有着龐大的地下水管網絡,嘟嘟是MY市的水管局長(就是管水管的啦),嘟嘟作爲水管局長的工作就是:每天供水公司可能要將一定量的水從x處送往y處,嘟嘟需要爲供水公司找到一條從A至B的水管的路徑,接着通過信息化的控制中心通知路徑上的水管進入準備送水狀態,等到路徑上每一條水管都準備好了,供水公司就可以開始送水了。嘟嘟一次只能處理一項送水任務,等到當前的送水任務完成了,才能處理下一項。
在處理每項送水任務之前,路徑上的水管都要進行一系列的準備操作,如清洗、消毒等等。嘟嘟在控制中心一聲令下,這些水管的準備操作同時開始,但由於各條管道的長度、內徑不同,進行準備操作需要的時間可能不同。供水公司總是希望嘟嘟能找到這樣一條送水路徑,路徑上的所有管道全都準備就緒所需要的時間儘量短。嘟嘟希望你能幫助他完成這樣的一個選擇路徑的系統,以滿足供水公司的要求。另外,由於MY市的水管年代久遠,一些水管會不時出現故障導致不能使用,你的程序必須考慮到這一點。
不妨將MY市的水管網絡看作一幅簡單無向圖(即沒有自環或重邊):水管是圖中的邊,水管的連接處爲圖中的結點。

輸入格式

第一行爲3個整數:N, M, Q分別表示管道連接處(結點)的數目、目前水管(無向邊)的數目,以及你的程序需要處理的任務數目(包括尋找一條滿足要求的路徑和接受某條水管壞掉的事實)。
以下M行,每行3個整數x, y和t,描述一條對應的水管。x和y表示水管兩端結點的編號,t表示準備送水所需要的時間。我們不妨爲結點從1至N編號,這樣所有的x和y都在範圍[1, N]內。
以下Q行,每行描述一項任務。其中第一個整數爲k:若k=1則後跟兩個整數A和B,表示你需要爲供水公司尋找一條滿足要求的從A到B的水管路徑;若k=2,則後跟兩個整數x和y,表示直接連接x和y的水管宣佈報廢(保證合法,即在此之前直接連接x和y尚未報廢的水管一定存在)。

輸出格式

每一項k=1的任務,你需要輸出一個數字和一個回車/換行符。
該數字表示:你尋找到的水管路徑中所有管道全都完成準備工作所需要的時間(當然要求最短)。

樣例輸入

4 4 3
1 2 2
2 3 3
3 4 2
1 4 2
1 1 4
2 1 4
1 1 4

樣例輸出

2
3

數據規模

N ≤ 1000
M ≤ 100000
Q ≤ 100000
測試數據中宣佈報廢的水管不超過5000條;且任何時候我們考慮的水管網絡都是連通的,即從任一結點A必有至少一條水管路徑通往任一結點B。


題解

算勁題嗎?好像算。。。
//先說一句,下面的描述中“水管”和“邊”是一個東西。。。
看一眼題目,讓最小值最大,顯然二分,讓路徑上的最大值最小,顯然想到最小生成樹(貪心一下即可)。跑一遍最小生成樹,兩點之間的路徑極大值即爲答案。
噁心的是刪邊問題。顯然不能在上一次討論的基礎上接着討論(這個“顯然”要感謝PhantasmDragon大佬)。但如果暴力搞,一次時間複雜度就是O(m)。結果本蒟蒻受了數據的蠱惑(測試數據中宣佈報廢的水管不超過5000條),一直在想如何卡常。。。。。
後來想能否找到快速查出倆連通塊之間的最短邊。想啊想。。。
最後,終於想起之前做的假期關樓(NKOJ3696),想起了可愛的猴子(NKOJ2107),反向考慮。
我們不妨將水管掛掉的事實反過來,從後往前討論,看作新水管出現。我們在沒有這些水管的情況下先跑一遍最小生成樹,每“出現”一根水管,就先算出這根水管兩端點的路徑極大值。如果極大值小於這根水管的值,那麼它沒用;否則,(根據貪心,),刪掉原路徑上值最大的邊,將此邊加入。
維護動態樹,用LCT。嗯 。
思路就是這樣。但還有幾個注意事項。首先,離線處理吧,這個顯然。所以有很多東西你需要記錄。其次,處理邊權的問題。把邊權轉爲兒子節點的點權的方法會G,因爲根在變。。。推薦老闆的方法:在兩端點之間再加一個點,這個點的點權即爲原來的邊權,其餘點邊權爲0 。還有,注意你要刪邊,所以記錄極大值時還要記錄位置。。。最後,要仔細,本蒟蒻把2打成1調了一個半小時QaQ。


代碼

鳴謝 機智的何老闆
鳴謝 高深莫測的何老闆

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <stack>
using namespace std;
const int Q=1210005;
struct dt{
	int x,y,v;
	bool ch;
}e[Q];
bool operator<(dt a,dt b)
{return a.x==b.x?a.y<b.y:a.x<b.x;}
bool cmp(dt a,dt b)
{return a.v<b.v;}
int tot,qu[4][Q],o[3][Q],ls[Q],rs[Q],v[Q],f[Q],an[Q],maxn[Q],lazy[Q],n,ans[Q];
//注意了!!!maxn[] 存的是編號!!!
int fa[Q];
int gf(int x)
{
	if(fa[x]!=x)fa[x]=gf(fa[x]);
	return fa[x];
}
int gm(int x,int y)
{v[0]=0;return v[maxn[x]]>v[maxn[y]]?maxn[x]:maxn[y];}
void update(int x)
{
	maxn[x]=gm(ls[x],rs[x]);
	if(v[x]>v[maxn[x]])maxn[x]=x;
}
void lx(int x)
{
	int y=f[x],z=f[y];
	if(z)if(ls[z]==y)ls[z]=x;
	else rs[z]=x;
	f[x]=z;
	rs[y]=ls[x];
	f[rs[y]]=y;
	f[y]=x;
	ls[x]=y;
	swap(an[x],an[y]);
	maxn[x]=maxn[y];
	update(y);
}
void rx(int x)
{
	int y=f[x],z=f[y];
	if(z)if(ls[z]==y)ls[z]=x;
	else rs[z]=x;
	f[x]=z;
	ls[y]=rs[x];
	f[ls[y]]=y;
	f[y]=x;
	rs[x]=y;
	swap(an[x],an[y]);
	maxn[x]=maxn[y];
	update(y);
}
void pd(int x)
{
	if(!lazy[x])return;
	lazy[x]=0;
	swap(ls[x],rs[x]);
	if(ls[x])lazy[ls[x]]^=1;
	if(rs[x])lazy[rs[x]]^=1;
}
int st[Q];
void splay(int x)
{
	int toap=0;
	for(int t=x;t;t=f[t])st[++toap]=t;
	while(toap)pd(st[toap--]);
	while(f[x])
	{
		int y=f[x],z=f[y];
		if(z)if(ls[z]==y)
			if(ls[y]==x)rx(y),rx(x);
			else lx(x),rx(x);
		else if(rs[y]==x)lx(y),lx(x);
			else rx(x),lx(x);
		else if(ls[y]==x)rx(x);
			else lx(x);
	}
}
void ac(int x)
{
	int y=0;
	while(x)
	{
		splay(x);
		if(rs[x])f[rs[x]]=0,an[rs[x]]=x;
		rs[x]=y;
		if(y)f[y]=x;
		update(x);
		y=x,x=an[x];
	}
}
void mr(int x)
{
	ac(x);
	splay(x);
	lazy[x]^=1;
}
void link(int x,int y)
{
	mr(x);
	an[x]=y;
}
void cut(int x,int y)
{
	mr(x);
	ac(y);
	splay(y);
	pd(y);
	an[y]=an[x]=ls[y]=f[x]=0;
	update(x),update(y);
}
int main()
{
	int m,q,cnt=0;
	scanf("%d%d%d",&n,&m,&q);
	for(int i=1;i<=n;i++)maxn[i]=fa[i]=i;
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].v);
		if(e[i].x>e[i].y)swap(e[i].x,e[i].y);
		e[i].ch=false;
	}
	sort(e+1,e+m+1);
	for(int i=1;i<=q;i++){
		scanf("%d%d%d",&qu[0][i],&qu[1][i],&qu[2][i]);
		if(qu[1][i]>qu[2][i])swap(qu[1][i],qu[2][i]);
		if(qu[0][i]==2)
		{
			int t=lower_bound(e+1,e+m+1,(dt){qu[1][i],qu[2][i],0,false})-e;
			e[t].ch=true;
			qu[3][i]=e[t].v;
		}
	}
	tot=n;
	sort(e+1,e+m+1,cmp);
	for(int i=1;i<=m&&cnt<n-1;i++)
	{
		if(e[i].ch)continue;
		int fx=gf(e[i].x),fy=gf(e[i].y);
		if(fx==fy)continue;
		fa[fx]=fy;
		v[++tot]=e[i].v;
		maxn[tot]=tot;
		o[1][tot]=e[i].x,o[2][tot]=e[i].y;
		link(tot,e[i].x),link(tot,e[i].y);
		++cnt;
	}
	for(int i=q;i;--i)
	{
		int x=qu[1][i],y=qu[2][i];
		if(qu[0][i]==2)
		{
			ans[i]=-1;
			int now=qu[3][i];
			mr(x),ac(y);
			splay(x);
			int temp=maxn[x];
			if(v[temp]<=now)continue;
			cut(temp,o[1][temp]),cut(temp,o[2][temp]);
			v[++tot]=now;
			maxn[tot]=tot;
			o[1][tot]=x,o[2][tot]=y;
			link(tot,x),link(tot,y);
		}
		else{
			mr(x);
			ac(y);
			splay(x);
			ans[i]=v[maxn[x]];
		}
	}
	for(int i=1;i<=q;i++)
		if(ans[i]!=-1)
			printf("%d\n",ans[i]);
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章