「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\n",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\n",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;
}
posted @ 2019-08-05 19:37  Eeis  阅读(366)  评论(0编辑  收藏  举报