CF603E Pastoral Oddities 优先队列+结论+LCT维护生成树

首先,一个神奇的结论:
一个合法的方案存在的条件是每一个联通块的节点数都是偶数个的.
这个可以用数学归纳法简单证一证.
证出这个后,我们只需动态加入每一个边,并查看一下有哪些边能够被删除(删掉后联通块依然合法).
对于维护加边,删边,我们用动态树.
对于枚举哪些边可以被删,我们可以用堆/set来维护.
由于每一条边最多只会加一次,也最多只会删一次,所以总时间复杂度为 $O(nlogm)$.

#include <cstdio> 
#include <queue> 
#include <cstring> 
#include <algorithm> 
#define lson t[x].ch[0]
#define rson t[x].ch[1] 
#define N 500000 
#define setIO(s) freopen(s".in","r",stdin) ,freopen(s".out","w",stdout) 
using namespace std; 
struct Edge {
	int u,v,c,id;      
	Edge(int u=0,int v=0,int c=0,int id=0):u(u),v(v),c(c),id(id){} 
	bool operator<(Edge a) const{
		return a.c>c; 
	}
}e[N];         
priority_queue<Edge>q; 
int sta[N],n,m,del[N];  
struct Node { 
	int ch[2],max,val,son,size,f,id,rev; 
}t[N]; 
int isrt(int x) {
	return !(t[t[x].f].ch[0]==x||t[t[x].f].ch[1]==x); 
}
int get(int x) {
	return t[t[x].f].ch[1]==x; 
}
void mark(int x) { 
	if(!x) return; 
	swap(lson,rson), t[x].rev^=1; 
}
void pushup(int x) {
	t[x].max=t[x].val,t[x].id=x; 
	t[x].max=max(t[x].max,max(t[lson].max,t[rson].max)); 
	if(t[lson].max==t[x].max) t[x].id=t[lson].id; 
	if(t[rson].max==t[x].max) t[x].id=t[rson].id; 
	t[x].size=t[x].son+t[lson].size+t[rson].size+(x<=n); 
}
void pushdown(int x) {
	if(t[x].rev) mark(lson), mark(rson), t[x].rev=0; 
}
void rotate(int x) {
	int old=t[x].f,fold=t[old].f,which=get(x); 
	if(!isrt(old)) 
		t[fold].ch[t[fold].ch[1]==old]=x; 
	t[old].ch[which]=t[x].ch[which^1],t[t[old].ch[which]].f=old; 
	t[x].ch[which^1]=old,t[old].f=x,t[x].f=fold; 
	pushup(old),pushup(x); 
}
void splay(int x) {
	int v=0,u=x,fa;
	for(sta[++v]=u;!isrt(u);u=t[u].f) sta[++v]=t[u].f;  
	for(int i=v;i>=1;--i) pushdown(sta[i]); 
	for(u=t[u].f;(fa=t[x].f)!=u;rotate(x)) 
		if(t[fa].f!=u) 
			rotate(get(fa)==get(x)?fa:x); 
}
void Access(int x) {
	int y=0; 
	while(x) {
		splay(x);  
		t[x].son-=t[y].size;  
		t[x].son+=t[rson].size; 
		rson=y,pushup(x),y=x,x=t[x].f;  
	}
}
void makeroot(int x) {
	Access(x),splay(x),mark(x); 
}
int findroot(int x) { 
	int u; 
	Access(x),splay(x); 
	while(x) { 
		pushdown(x);  
		u=x,x=lson; 
	} 
	return u; 
}
void split(int x,int y) {
	makeroot(x),Access(y),splay(y); 
}     
void link(int x,int y) {
	makeroot(x), makeroot(y),t[x].f=y, t[y].son+=t[x].size,pushup(y);  
}
void cut(int x,int y) {
	makeroot(x),Access(y),splay(y); 
	t[y].ch[0]=t[x].f=0; 
	pushup(y);        
}
int main() { 
	int i,j; 
	// setIO("input"); 
	scanf("%d%d",&n,&m); 
	if(n%2==1) {
		for(i=1;i<=m;++i) printf("-1\n");  
		return 0; 
	}
	int cnt=n; 
    for(i=1;i<=m;++i) {
    	int u,v,c; 
    	scanf("%d%d%d",&u,&v,&c);       
    	e[i]=Edge(u,v,c,i+n); 
    	int x=findroot(u),y=findroot(v); 
    	if(x!=y) { 
    		int now=i+n;  
    		makeroot(u),makeroot(v);  
    		if(t[u].size%2==1&&t[v].size%2==1) cnt-=2; 
    		t[now].val=c;  
    		link(u,now),link(now,v);              
    		q.push(Edge(u,v,c,now)); 
    	}
    	else {  
    		split(u,v); 
    		if(t[v].max>c) {
    			int cc=t[v].id,xx=e[cc-n].u,yy=e[cc-n].v,now=i+n;  
    			cut(cc,xx),cut(cc,yy), t[now].val=c; 
    			del[cc]=1; 
    			link(u,now),link(now,v);   
    			q.push(Edge(u,v,c,now));    
    		}  
    	} 
    	if(cnt) printf("-1\n"); 
    	else {
    		while(1) { 
    			while(!q.empty()&&del[q.top().id]) q.pop();  
    			int xx=q.top().u,yy=q.top().v,cc=q.top().id,X,Y; 
    			makeroot(cc);   
    			Access(xx),splay(xx),X=t[xx].size-t[cc].size; 
    			Access(yy),splay(yy),Y=t[yy].size-t[cc].size; 
    			if(X%2==0&&Y%2==0) 
    				cut(xx,cc),cut(yy,cc),q.pop();  
    			else break; 
    		}
    		printf("%d\n",q.top().c); 
    	}
    }
	return 0; 
}

  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值