1. 程式人生 > >BZOJ 4736/UOJ #274. 【清華集訓2016】溫暖會指引我們前行 LCT邊權操作

BZOJ 4736/UOJ #274. 【清華集訓2016】溫暖會指引我們前行 LCT邊權操作


維護動態最大生成樹

最開始YY了一個 線段樹分治 kruskal重構樹

然後覺得複雜度不對? 不過BJ對kruskal重構樹也僅僅算理解 沒寫過。。

希望有人帶帶 QWQ 告訴我對不對、怎麼做哦~

LCT維護最大生成樹

加入一條邊時

若兩點未聯通 直接加

否則找到兩點路徑上最小的邊 看能不能替換掉

#include<cmath>
#include<ctime>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<string>
#include<bitset>
#include<queue>
#include<set>
#include<map>
using namespace std;

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

const int N=400100,inf=0X3f3f3f3f;

int n;

int fa[N],ch[N][2];
int mn[N],sum[N],tim[N],len[N];
bool rev[N];

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

inline void pushup(int x)
{
	mn[x]=x;
	int ls=ch[x][0],rs=ch[x][1];
	if(ls && tim[mn[ls]]<tim[mn[x]]) mn[x]=mn[ls];
	if(rs && tim[mn[rs]]<tim[mn[x]]) mn[x]=mn[rs];
	sum[x]=sum[rs]+sum[ls]+len[x];
}

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

void getdown(int x)
{if(!isroot(x))getdown(fa[x]);pushdown(x);}

inline void rotate(int x)
{
	int y=fa[x],z=fa[y],l,r;
	l=(ch[y][1]==x);r=l^1;
	if(!isroot(y)) ch[z][ch[z][1]==y]=x;
	fa[x]=z;fa[y]=x;fa[ch[x][r]]=y;
	ch[y][l]=ch[x][r];ch[x][r]=y;
	pushup(y);pushup(x);
}

void splay(int x)
{
	getdown(x);
	int y,z;
	while(!isroot(x))
	{
		y=fa[x];z=fa[y];
		if(!isroot(y))
		{
			if((ch[z][0]==y)^(ch[y][0]==x)) rotate(x);
			else rotate(y);
		}
		rotate(x);
	}
}

void access(int x)
{int t=0;while(x){splay(x);ch[x][1]=t;pushup(x);t=x;x=fa[x];}}

void rever(int x)
{access(x);splay(x);rev[x]^=1;}

int find(int x)
{access(x);splay(x);while(ch[x][0])x=ch[x][0];splay(x);return x;}

void split(int u,int v)
{rever(u);access(v);splay(v);}

void link(int u,int v)
{rever(u);fa[u]=v;}

void cut(int u,int v)
{split(u,v);fa[u]=0;ch[v][0]=0;pushup(u);pushup(v);}

int query_sum(int u,int v)
{split(u,v);return sum[v];}

int U[N],V[N];

int main()
{
	n=read();int Q=read();
	register int i,j,u,v,pos,tmp;
	for(i=1;i<=n;++i) tim[i]=inf,mn[i]=i;
	char opt[10];
	while(Q--)
	{
		scanf("%s",opt);
		switch(opt[0])
		{
			case 'f':
				pos=read()+n+1;
				u=U[pos]=read()+1;v=V[pos]=read()+1;
				mn[pos]=pos;
				tim[pos]=read();sum[pos]=len[pos]=read();
				if(find(u)!=find(v))
					link(u,pos),link(v,pos);
				else
				{
					split(u,v);
					tmp=mn[v];i=U[tmp];j=V[tmp];
					if(tim[tmp]<tim[pos])
						cut(tmp,i),cut(tmp,j),
						link(pos,u),link(pos,v);
				}
				break;
			case 'm':
				u=read()+1;v=read()+1;
				if(find(u)==find(v))
					print(query_sum(u,v)),puts("");
				else puts("-1");
				break;
			case 'c':
				pos=read()+n+1;
				splay(pos);
				len[pos]=read();
				pushup(pos);
				break;
		}
	}
	return 0;
}