BZOJ 2594: [Wc2006]水管局长数据加强版(LCT + 克鲁斯卡尔算法)

博客讲述了在BZOJ 2594题目中,如何应对LCT数据加强版的问题。作者强调LCT的常数优化并非易事,通过离线倒序加边动态维护最小生成树,以及针对删边编号的二分查找和对持久存在的边应用克鲁斯卡尔算法,成功避免TLE并实现AC。
摘要由CSDN通过智能技术生成

题目
LCT是不可能常数小的,永远都不可能常数小的。
离线倒序加边动态维护最小生成树不用讲了。
有谁知道,多少像我一样的OIER打了代码一直TLE后,几度质疑自己的无言的选择,有谁知道,在这个梦想如钻石一般珍贵的年华,人机对峙,侧身西望的孤寂,曾经的LCT之梦,也化作“这数据结构也就跑跑小数据”“以后还是打树剖吧”间那一抹苦笑。
然而,LCT并不是TLE的原因。。。。。。
数据加强?
I t ′ s   a   t r a p . {\rm {It's \ a \ trap. }} Its a trap.
这个题的重点在于:在LCT本身之外的地方寻找常数优化。
1:找删边的编号不要写map!排序后二分。。。。。。
2:对于一直存在的边做克鲁斯卡尔算法。。。。。。
然后在死亡边缘OB。

AC Code:

#include<bits/stdc++.h>
#define maxn 1000005
using namespace std;

char cb[1<<15],*cs=cb,*ct=cb;
#define getc() (cs==ct&&(ct=(cs=cb)+fread(cb,1,1<<15,stdin),cs==ct)?0:*cs++)

void read(int &res){
	char ch;
	for(;!isdigit(ch=getc()););
	for(res=ch-'0';isdigit(ch=getc());res=res*10+ch-'0');
}
void print(int x){
	static char s[15],*s1;s1=s;
	if(!x) *s1++='0';if(x<0) *s1++='-';
	while(x) *s1++=x%10+'0',x/=10;
	while(s1--!=s) putchar(*s1);
}

struct edge{
	int u,v,w,tim;
	bool operator <(const edge &B)const{ return tim==B.tim?w==B.w?u==B.u?v<B.v:u<B.u:w<B.w:tim>B.tim; }
}e[maxn];
bool cmp(const int &u,const int &v){ return e[u].u==e[v].u?e[u].v<e[v].v:e[u].u<e[v].u; }
bool cmp2(const int &u,const int &v){ return e[u].tim==e[v].tim?e[u].w==e[v].w?e[u].u==e[v].u?e[u].v<e[v].v:e[u].u<e[v].u:e[u].w<e[v].w:e[u].tim>e[v].tim; }
struct query{
	int u,v,tim;
	bool operator <(const query &B)const{ return tim==B.tim?u==B.u?v<B.v:u<B.u:tim>B.tim; }
}q[maxn];
int cnt_q,c[maxn];
int n,m,Q,lb[maxn][2];

int F[maxn];
int Find(int a){return !F[a]?a:F[a]=Find(F[a]);}

namespace LCT{
	int fa[maxn],ch[maxn][2],rev[maxn],Max[maxn],val[maxn],tot;
	#define il inline 
	#define pa fa[x]
	il int inr(int x){ return ch[pa][1]==x; }
	il int isr(int x){ return ch[pa][0]!=x&&ch[pa][1]!=x; }
	il void dt(int x){
		if(rev[x]){
			swap(ch[x][0],ch[x][1]),rev[x]=0;
			if(ch[x][0]) rev[ch[x][0]]^=1;
			if(ch[x][1]) rev[ch[x][1]]^=1;
		}
	}
	il void dtpath(int x){ if(!isr(x)) dtpath(pa); dt(x); }
	il void upd(int x){
		Max[x] = x;
		if(val[Max[ch[x][0]]] > val[Max[x]]) Max[x] = Max[ch[x][0]];
		if(val[Max[ch[x][1]]] > val[Max[x]]) Max[x] = Max[ch[x][1]];
	}
	il void rot(int x){
		int y=fa[x],z=fa[y],c=inr(x);
		if(!isr(y)) ch[z][inr(y)]=x;
		(ch[y][c]=ch[x][!c])&&(fa[ch[y][c]]=y);
		fa[fa[ch[x][!c]=y]=x]=z;
		upd(y),upd(x);
	}
	il void splay(int x){
		dtpath(x);
		for(;!isr(x);rot(x))
			if(!isr(pa)) rot(inr(pa)==inr(x)?pa:x);
	}
	il int access(int x,int y=0){
		for(;x;x=fa[y=x]) splay(x),ch[x][1]=y,upd(x);
		return y;
	}
	il void bert(int x){
		access(x),splay(x),rev[x]^=1;
	}
	il int split(int x,int y){
		bert(x),access(y),splay(y);
		return y;
	}
	il int querymax(int x,int y){
		return Max[split(x,y)];
	}
	il void link(int x,int y){
		bert(x),fa[x]=y;
	}
	il void cut(int x,int y){
		bert(x),access(y),splay(y);
		fa[x]=ch[y][0]=0;
		upd(y);
	}
	il void insert(int x,int y,int w){
		if(Find(x)!=Find(y)){
			val[++tot] = w;
			Max[tot]=tot;
			fa[tot]=x,bert(y),fa[y]=tot;
			lb[tot][0]=x,lb[tot][1]=y;
			F[Find(x)] = Find(y);
			return;
		}
		int tmp = querymax(x,y);
		if(w<val[tmp]){
			cut(tmp,lb[tmp][0]);
			cut(tmp,lb[tmp][1]);
			val[tmp]=w;
			Max[tmp]=tmp;
			fa[tmp]=x,bert(y),fa[y]=tmp;
			lb[tmp][0]=x,lb[tmp][1]=y;
		}
	}
}
int ans[maxn],tp;
int main(){
	//int t1 = clock();
	//freopen("1.in","r",stdin);
	//freopen("1.out","w",stdout);
	read(n),read(m),read(Q);LCT::tot=n;
	for(int i=1;i<=m;i++){
		read(e[i].u),read(e[i].v),read(e[i].w);
		if(e[i].u>e[i].v) swap(e[i].u,e[i].v);
		c[i] = i;
 	}
	sort(c+1,c+1+m,cmp);
	for(int i=1;i<=Q;i++){
		int op,x,y;
		read(op),read(x),read(y);
		if(x>y) swap(x,y);
		if(op == 1) q[++cnt_q].tim=i,q[cnt_q].u=x,q[cnt_q].v=y;
		else{
			int L = 1 , R = m , mid;
			for(;L<R;){
				mid = (L+R) >> 1;
				if(e[c[mid]].u<x || (e[c[mid]].u==x && e[c[mid]].v<y)) L = mid + 1;
				else R = mid;`
			}
			e[c[L]].tim = i;
		}
	}
	for(int i=1;i<=m;i++) if(!e[i].tim) e[i].tim=Q+1;
	sort(c+1,c+1+m,cmp2);
	int j=1;
	for(;j<=m && e[c[j]].tim==Q+1;j++)
		if(Find(e[c[j]].u)!=Find(e[c[j]].v))
			LCT::insert(e[c[j]].u,e[c[j]].v,e[c[j]].w);
	sort(q+1,q+1+cnt_q);
	for(int i=1;i<=cnt_q;i++){
		for(;j<=m && e[c[j]].tim>q[i].tim;j++)
			LCT::insert(e[c[j]].u,e[c[j]].v,e[c[j]].w);
		ans[tp++] = LCT::val[LCT::querymax(q[i].u,q[i].v)];
	}
	for(;tp;) print(ans[--tp]),puts("");
	//freopen("CON","w",stdout);
	//printf("%d\n",clock()-t1);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值