1. 程式人生 > >【bzoj2594】[Wc2006]水管局長資料加強版 link cut tree

【bzoj2594】[Wc2006]水管局長資料加強版 link cut tree

好久的坑了,今天終於填上了。

一直想總結一下LCT,結果發現難題都不會做。

離線處理,因為刪邊比較難做,所以我們倒著做變成加邊操作。

問題轉化成加邊維護最小生成樹,用lct維護一下最大的邊是哪一條,一旦新加入的邊形成環了,那麼看一看環上最大的邊和新加入的邊哪個大,如果新加入的邊小,那麼刪除原來的邊,加入這一條邊。

竟然1A,簡直不可思議,不過時間慢成狗。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<iostream>
#define maxn 1500010

using namespace std;

struct yts
{
	int x,y,id,z;
	int tag;
}e[1000010];

struct yts1
{
	int op,x,y,ans,id;
}q[100010];

int fa[maxn],ch[maxn][2],val[maxn],mx[maxn];
bool rev[maxn];
int f[100010];
int n,m,T,tot,num;

inline int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}

bool cmp1(yts x,yts y)
{
	return x.x<y.x || (x.x==y.x && x.y<y.y);
}

int find(int x,int y)
{
	int l=1,r=m,ans;
	while (l<=r)
	{
		int mid=(l+r)/2;
		if (e[mid].x==x && e[mid].y==y) return mid;
		if (e[mid].x<x || (e[mid].x==x && e[mid].y<y)) ans=mid,l=mid+1;
		else r=mid-1;
	}
	return ans;
}

bool cmp2(yts x,yts y)
{
	return x.z<y.z;
}

bool cmp3(yts x,yts y)
{
	return x.id<y.id;
}

int dir(int x)
{
	return x==ch[fa[x]][1];
}

int isroot(int x)
{
	return !(x==ch[fa[x]][0] || x==ch[fa[x]][1]);
}

void push_up(int x)
{
	mx[x]=x;
	if (val[mx[ch[x][0]]]>val[mx[x]]) mx[x]=mx[ch[x][0]];
	if (val[mx[ch[x][1]]]>val[mx[x]]) mx[x]=mx[ch[x][1]];
}

void reverse(int x)
{
	rev[x]^=1;
	swap(ch[x][0],ch[x][1]);
}

void push_down(int x)
{
	if (rev[x])
	{
		if (ch[x][0]) reverse(ch[x][0]);
		if (ch[x][1]) reverse(ch[x][1]);
		rev[x]^=1;
	}
}

void rotate(int x)
{
	int y=fa[x],z=fa[y],b=dir(x),a=ch[x][!b],c=dir(y);
	if (!isroot(y)) ch[z][c]=x;
	fa[x]=z;fa[y]=x;ch[x][!b]=y;ch[y][b]=a;
	if (a) fa[a]=y;
	push_up(y);push_up(x); 
}

void down(int x)
{
	if (!isroot(x)) down(fa[x]);
	push_down(x);
}

void splay(int x)
{
	down(x);
	while (!isroot(x))
	{
		int y=fa[x];
		if (isroot(y)) rotate(x);
		else
		{
			int b=dir(x),c=dir(y);
			if (b^c) 
			{
				rotate(x);rotate(x);
			}
			else
			{
				rotate(y);rotate(x);
			}
		}
	}
}

void access(int x)
{
	for (int y=0;x;y=x,x=fa[x])
	{
		splay(x);
		ch[x][1]=y;
		push_up(x);
	}
}

void make_root(int x)
{
	access(x);
	splay(x);
	reverse(x);
}

void cut(int x,int y)
{
	make_root(x);
	access(x);
	splay(y);
	fa[y]=0;
}

void link(int x,int y)
{
	make_root(x);
	fa[x]=y;
}

int query(int x,int y)
{
	make_root(x);
	access(y);
	splay(y);
	return mx[y];
}

int find(int x)
{
	if (f[x]==x) return x;
	else return f[x]=find(f[x]);
}

int main()
{
	n=read();m=read();T=read();
	for (int i=1;i<=m;i++) {e[i].x=read();e[i].y=read();e[i].z=read();if (e[i].x>e[i].y) swap(e[i].x,e[i].y);}
	sort(e+1,e+m+1,cmp2);
	for (int i=1;i<=m;i++) {e[i].id=i;val[i+n]=e[i].z;mx[i+n]=i+n;}
	sort(e+1,e+m+1,cmp1);
	for (int i=1;i<=T;i++)
	{
		q[i].op=read();q[i].x=read();q[i].y=read();
		if (q[i].x>q[i].y) swap(q[i].x,q[i].y);
		if (q[i].op==2)
		{
			int x=find(q[i].x,q[i].y);
			q[i].id=e[x].id;
			e[x].tag=1;
		}
	}
	sort(e+1,e+m+1,cmp3);
	for (int i=1;i<=n;i++) f[i]=i;
	for (int i=1;i<=m;i++)
	  if (!e[i].tag)
	  {
	  	int f1=find(e[i].x),f2=find(e[i].y);
	  	if (f1!=f2)
	  	{
	  		num++;
	  		link(e[i].x,i+n);link(e[i].y,i+n);
	  		f[f1]=f2;
	  		if (num==n-1) break;
	  	}
	  }
	for (int i=T;i>=1;i--)
	{
		if (q[i].op==1) q[i].ans=val[query(q[i].x,q[i].y)];
		else
		{
			int x=query(q[i].x,q[i].y);
			if (e[q[i].id].z<val[x]) cut(e[x-n].x,x),cut(e[x-n].y,x),link(q[i].x,q[i].id+n),link(q[i].y,q[i].id+n);
		}
	}
	for (int i=1;i<=T;i++)
	  if (q[i].op==1) printf("%d\n",q[i].ans);
	return 0;
}