• 「BalkanOI 2018 Day1」Minmaxtree


    「BalkanOI 2018 Day1」Minmaxtree

    每个点都有一个最大和最小权值的限制。

    然后每一个权值的限制都必须要取到。

    每个点显然可以直接让他取到最大或最小权值。

    可以想到每个点匹配一个权值。

    不就是一个二分图吗。。。

    每个点连向最大和最小权值,然后跑dinic,输出方案,当然本题匈牙利可以跑过。

    接下来就是要求每个点的权值限制:可以用LCT直接链标记,也可以离线下来,排序后,依次加入,用一个并查集跳过已经访问过的点。

    #include<bits/stdc++.h>
    #define rep(q,a,b) for(int q=a,q##_end_=b;q<=q##_end_;++q)
    #define dep(q,a,b) for(int q=a,q##_end_=b;q>=q##_end_;--q)
    #define mem(a,b) memset(a,b,sizeof a )
    #define debug(a) cerr<<#a<<' '<<a<<"___"<<endl
    using namespace std;
    void in(int &r){
    	static char c;
    	r=0;
    	while(c=getchar(),!isdigit(c));
    	do r=(r<<1)+(r<<3)+(c^48);
    	while(c=getchar(),isdigit(c));
    }
    const int mn=70010;
    int head[mn<<1],to[mn<<3],ne[mn<<3],cnt1,W[mn<<3],n;
    #define link1(a,b) link_edge1(a,b),link_edge1(b,a)
    #define link_edge1(a,b) to[++cnt1]=b,ne[cnt1]=head[a],head[a]=cnt1
    #define travel(x) for(int q(head[x]);q;q=ne[q])
    struct edge{
    	int x,y;
    }e[mn];
    void link(int x,int y);
    int cnt;
    void pre_dfs(int f,int x){
    	travel(x)if(to[q]!=f)e[++cnt]={x,to[q]},link(to[q],cnt+n),link(cnt+n,x),pre_dfs(x,to[q]);
    }
    int son[mn<<1][2],fa[mn<<1];
    bool mark[mn<<1];
    int Min[mn<<1],Max[mn<<1];
    int minv[mn<<1],maxv[mn<<1];
    bool noroot(int x){
    	return x==son[fa[x]][0]||x==son[fa[x]][1];
    }
    void rotate(int x){
    	int y=fa[x],z=fa[y],d=x==son[y][1];
    	if(noroot(y))son[z][y==son[z][1]]=x;
    	son[y][d]=son[x][!d];
    	fa[son[x][!d]]=y;
    	son[x][!d]=y;
    	fa[x]=z,fa[y]=x;
    }
    int sta[mn<<1],tp;
    void res(int x){
    	if(!x)return;
    	swap(son[x][0],son[x][1]);
    	mark[x]^=1;
    }
    void min_mark(int x,int v){
    	if(!x)return;
    	if(!minv[x])minv[x]=v;
    	else minv[x]=max(v,minv[x]);
    	if(!Min[x])Min[x]=v;
    	else Min[x]=max(Min[x],v);
    }
    void max_mark(int x,int v){
    	if(!x)return;
    	if(!maxv[x])maxv[x]=v;
    	else maxv[x]=min(v,maxv[x]);
    	if(!Max[x])Max[x]=v;
    	else Max[x]=min(Max[x],v);
    }
    void push_down(int x){
    	int ls=son[x][0],rs=son[x][1];
    	if(mark[x]){
    		res(ls);
    		res(rs);
    		mark[x]=0;
    	}
    	if(Min[x]){
    		min_mark(ls,Min[x]);
    		min_mark(rs,Min[x]);
    		Min[x]=0;
    	}
    	if(Max[x]){
    		max_mark(ls,Max[x]);
    		max_mark(rs,Max[x]);
    		Max[x]=0;
    	}
    }
    void splay(int x){
    	tp=0;
    	int now=x;
    	while(noroot(now))sta[++tp]=now,now=fa[now];
    	sta[++tp]=now;
    	dep(q,tp,1)push_down(sta[q]);
    	while(noroot(x)){
    		int y=fa[x];
    		if(noroot(y))(x==son[y][1])==(y==son[fa[y]][1])?rotate(y):rotate(x);
    		rotate(x);
    	}
    }
    void access(int x){
    	for(int y=0;x;y=x,x=fa[x])splay(x),son[x][1]=y;
    }
    void makeroot(int x){
    	access(x),splay(x),res(x);
    }
    void split(int x,int y){
    	makeroot(x);
    	access(y),splay(y);
    }
    void link(int x,int y){
    	fa[x]=y;
    }
    int px[mn],ll[mn],rr[mn],hd=0;
    void solve(){
    	int a,b,v,Q;
    	in(Q);
    	char c;
    	while(Q--){
    		while(c=getchar(),!isalpha(c));
    		in(a),in(b),in(v);
    		px[++hd]=v;
    		split(a,b);
    		if(c=='M')max_mark(b,v);
    		else min_mark(b,v);
    	}
    }
    void get_min_max(){ 
    	sort(px+1,px+hd+1);
    	rep(q,1,n-1){
    		splay(n+q);
    		ll[q]=minv[n+q],rr[q]=maxv[n+q];
    	}
    }
    void clear_edge(){
    	rep(q,1,n)head[q]=0;
    	cnt1=1;
    }
    void link_edge(int x,int y,int z){
    	to[++cnt1]=y,ne[cnt1]=head[x],head[x]=cnt1;
    	W[cnt1]=z;
    }
    void link_w(int x,int y,int z){
    	link_edge(x,y,z);
    	link_edge(y,x,0);
    }
    int S,T,tot_node;
    void build_graph(){
    	S=n-1+hd+1;
    	T=S+1;
    	tot_node=T;
    	rep(q,1,n-1)link_w(S,q,1);
    	rep(q,1,hd)link_w(q+n-1,T,1);
    	rep(q,1,n-1){
    		if(ll[q])ll[q]=lower_bound(px+1,px+hd+1,ll[q])-px,link_w(q,ll[q]+n-1,1);
    		if(rr[q])rr[q]=lower_bound(px+1,px+hd+1,rr[q])-px,link_w(q,rr[q]+n-1,1);
    	}
    }
    int depth[mn<<1],cur[mn<<1],que[mn<<1];
    bool bfs(){
    	rep(q,1,tot_node)depth[q]=-1;
    	int l=0,r=0;
    	que[++r]=S;
    	depth[S]=1;
    	while(l<r){
    		int now=que[++l];
    		travel(now)if(depth[to[q]]==-1&&W[q]){
    			depth[to[q]]=depth[now]+1;
    			que[++r]=to[q];
    			if(to[q]==T)return 1;
    		}
    	}
    	return 0;
    }
    int dfs(int x,int flow){
    	if(!flow||x==T)return flow;
    	int used=0;
    	for(int &q=cur[x];q;q=ne[q])if(depth[to[q]]==depth[x]+1){
    		int fl=dfs(to[q],min(flow-used,W[q]));
    		W[q]-=fl;
    		W[q^1]+=fl;
    		used+=fl;
    		if(used==flow)return used;
    	}
    	if(!used)depth[x]=-1;
    	return used;
    }
    void bipartite_match(){
    	while(bfs()){
    		rep(q,1,tot_node)cur[q]=head[q];
    		dfs(S,1e9);
    	}
    }
    bool mk[mn];
    const int Rand_lim=1e9;
    void out(){
    	rep(w,1,n-1){
    		bool ok=0;
    		travel(w)if(to[q]!=S&&to[q]>=n&&W[q]==0){
    			printf("%d %d %d
    ",e[w].x,e[w].y,px[to[q]-(n-1)]);
    			mk[to[q]-(n-1)]=1;
    			ok=1;
    		}
    		if(!ok)printf("%d %d %d
    ",e[w].x,e[w].y,rr[w]?px[rr[w]]:px[ll[w]]);
    	}
    }
    int main(){
    	freopen("minmaxtree.in","r",stdin);
    	freopen("minmaxtree.out","w",stdout);
    	srand(time(NULL));
    	int a,b;
    	in(n);
    	rep(q,2,n)in(a),in(b),link1(a,b);
    	pre_dfs(0,1);
    	
    	solve();
    	
    	get_min_max();
    	
    	clear_edge();
    	
    	build_graph();
    	
    	bipartite_match();
    	
    	out();
    	return 0;
    }
    
  • 相关阅读:
    《Java从入门到放弃》入门篇:springMVC数据校验
    《Java从入门到放弃》入门篇:springMVC数据传递 (二)
    《Java从入门到放弃》入门篇:springMVC数据传递
    《Java从入门到放弃》入门篇:springMVC基本用法
    《Java从入门到放弃》入门篇:spring中AOP的配置方式
    《Java从入门到放弃》入门篇:spring中IOC的注入姿势
    《Java从入门到放弃》入门篇:Struts2的拦截器基本语法
    《Java从入门到放弃》入门篇:Struts2的常用验证方式(二)
    26计算限制的异步操作02-CLR
    26计算限制的异步操作01-CLR
  • 原文地址:https://www.cnblogs.com/klauralee/p/11305097.html
Copyright © 2020-2023  润新知