• 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
    ");  
    		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
    "); 
        	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
    ",q.top().c); 
        	}
        }
    	return 0; 
    }
    

      

  • 相关阅读:
    C语言面向对象编程(五):单链表实现(转)
    pthread_barrier_init,pthread_barrier_wait简介(转)
    Linux信号(signal) 机制分析(转)
    Linux 进程间通信 --- 信号通信 --- signal --- signal(SIGINT, my_func); --- 按键驱动异步通知(转)
    Linux 多线程环境下 进程线程终止函数小结(转)
    批量杀进程 ps awk grep
    C++中的INL(转)
    gdb调试多进程和多线程命令(转)
    转: 基于netty+ protobuf +spring + hibernate + jgroups开发的游戏服务端
    转:全栈工程师的知识栈列表
  • 原文地址:https://www.cnblogs.com/guangheli/p/11418230.html
Copyright © 2020-2023  润新知