• Codeforces 1322 F : Assigning Fares


    Link

    显然可以将条件拆成相邻边之间的方向要相同/不同。考虑二分答案 (K)

    我们硬点当前节点 ( ext{x}) 到父亲 ( ext{fa}) 的边的方向是 ( ext{x} o ext{fa})。设 (f[x]) 为最小的合法的填在 (x) 上的数,当然,如果边反向的话最大的合法的数即为 (k+1-f[x])

    现在考虑每一组互相关联的边,两个方向上的 (f) 的最大值分别是 (A_1,A_2) 。和父亲连的连通块已经确定了哪个是 (L) 限制,哪个是 (R) 限制。

    最后我们需要将 (A_1,A_2) 一个去更新 (L),一个去更新 (R),最后要 (L + R < K)

    我们考虑还未确定放哪边的数,可以发现的是我们将 (A_1,A_2) 较大的放到一组,较小的放到一组一定是最优秀的。

    之后只需要枚举一下方向就行了。

    复杂度 (O(nlog n))

    代码

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 5e5+5;
    typedef pair<int,int> pi;
    vector<int> g[N],id[N];
    int n,m;
    struct UST{
    	vector<int> fa,c;
    	inline void init(int n){
    		fa.resize(n+1);
    		c.resize(n+1);
    		for(int i=0;i<=n;i++)fa[i] = i;
    	}
    	inline int find(int x){
    		if(fa[x]==x)return x;
    		else{
    			find(fa[x]); c[x] ^= c[fa[x]]; fa[x] = fa[fa[x]];
    			return fa[x];
    		}
    	}
    	inline void mrg(int x,int y){
    		find(x),find(y);
    		if(fa[x]^fa[y]){
    			c[fa[x]]=1^c[x]^c[y];fa[fa[x]]=fa[y];
    		}else if(c[x]==c[y]){puts("-1");exit(0);/*no solution.*/}
    	}
    }us[N];
    
    int p[N];//to calc merge x , fa[x], fa[fa[x]]
    int p2[N];//to calc ifedge is occipied
    int dep[N],anc[N][20];
    
    inline void adde(int u,int v){g[u].push_back(v);id[u].push_back(-1);}
    inline void dfs(int x,int pre){
    	anc[x][0]=pre;dep[x] = dep[pre]+1;
    	for(int i=1;i<=19;i++)anc[x][i]=anc[anc[x][i-1]][i-1];
    	us[x].init(g[x].size());
    	for(size_t i=0;i<g[x].size();i++){
    		int v=g[x][i];if(v==pre)continue;
    		dfs(v,x);
    	}
    }
    vector<pi> opts[N];
    inline void perform(int x,int y){
    	if(x==y)return;
    	if(dep[x]<dep[y])swap(x,y);
    	int _x=x;
    	p2[x]++,p2[y]++;
    	for(int i=19;~i;i--)if(dep[anc[x][i]]>=dep[y])x=anc[x][i];
    	if(x!=y){
    		p[_x]++,p[y]++;
    		for(int i=19;~i;i--){
    			if(anc[x][i]!=anc[y][i])x=anc[x][i],y=anc[y][i];
    		}p[x]--,p[y]--;
    		opts[anc[x][0]].push_back(pi(x,y));
    		p2[anc[x][0]]-=2;
    	}else{
    		x=_x;p[x]++;for(int i=19;~i;i--)if(dep[anc[x][i]]>dep[y])x=anc[x][i];p[x]--;
    		p2[y]-=2;
    	}
    }
    int K,f[N],temp_id[N];
    bool FLAG;
    vector<int> h[N][2];
    inline void pref(int x,int pre){
    	for(int j=0;j<2;j++)h[x][j].resize(g[x].size());
    	for(size_t i=0;i<g[x].size();i++){
    		int v=g[x][i];if(v==pre)continue;
    		pref(v,x);p[x]+=p[v];p2[x]+=p2[v];
    	}
    	for(size_t i=0;i<g[x].size();i++){
    		int v=g[x][i];
    		if(v==pre&&p2[x])id[x][i]=i;
    		else if(p2[v])id[x][i]=i;
    	}
    	for(size_t i=0;i<g[x].size();i++){int v=g[x][i];temp_id[v]=id[x][i];}
    	for(size_t i=0;i<g[x].size();i++){
    		int v=g[x][i];if(v!=pre&&p[v]){
    			us[x].mrg(temp_id[v],temp_id[pre]);
    		}
    	}
    	for(size_t i=0;i<opts[x].size();i++){
    		int a=opts[x][i].first,b=opts[x][i].second;
    		us[x].mrg(temp_id[a],temp_id[b]);
    	}
    	for(size_t i=0;i<g[x].size();i++){
    		if(id[x][i]!=-1){
    			us[x].find(id[x][i]);
    		}
    	}
    }/* to make the union set */
    int dir[N];
    inline void Dp(int x,int pre){
    	f[x]=1;
    	for(int i=0;i<(int)g[x].size();i++)h[x][0][i]=h[x][1][i]=0;
    	int qwq[2]={0,0};
    	int idd=-1,cidd=0;
    	for(size_t i=0;i<g[x].size();i++){
    		if(g[x][i]==pre){
    			if(id[x][i]!=-1)idd=us[x].fa[id[x][i]],cidd=us[x].c[id[x][i]];
    		}
    	}
    	for(size_t i=0;i<g[x].size();i++){
    		int v=g[x][i];if(v==pre)continue;
    		Dp(v,x);
    		if(id[x][i]!=-1){
    			if(us[x].fa[id[x][i]]==idd){
    				dir[v]=(us[x].c[id[x][i]]==cidd);
    				if(us[x].c[id[x][i]]!=cidd)qwq[0]=max(qwq[0],f[v]);
    				else qwq[1]=max(qwq[1],f[v]);
    			}
    			else{
    				h[x][us[x].c[id[x][i]]][us[x].fa[id[x][i]]]=max(h[x][us[x].c[id[x][i]]][us[x].fa[id[x][i]]],f[v]);
    			}
    		}
    	}
    	int qaq[2]={0,0};
    	for(size_t i=0;i<g[x].size();i++){
    		int a=min(h[x][0][i],h[x][1][i]), b=max(h[x][0][i],h[x][1][i]);
    		qaq[0]=max(qaq[0],a);
    		qaq[1]=max(qaq[1],b);
    	}
    	int type=0;
    	if(max(qaq[0],qwq[0])+max(qwq[1],qaq[1])<K){
    		f[x]=max(qaq[0],qwq[0])+1;
    	}
    	else{
    		type=1;
    		if(max(qaq[1],qwq[0])+max(qwq[1],qaq[0])<K)f[x]=max(qaq[1],qwq[0])+1;
    		else FLAG=0,f[x]=1;
    	}
    	for(size_t i=0;i<g[x].size();i++){
    		int v=g[x][i];if(v==pre)continue;
    		if(id[x][i]!=-1){
    			if(us[x].fa[id[x][i]]==idd)continue;
    			int idx = us[x].fa[id[x][i]], c = us[x].c[id[x][i]];
    			int cc = c^(h[x][0][idx]>h[x][1][idx])^type;
    			dir[v]=cc;
    		}
    	}
    }
    
    inline bool check(int k){
    	K=k,FLAG=1;
    	Dp(1,0);
    	return FLAG;
    }
    
    bool t[N];
    int ans[N];
    
    inline void getans(int x,int pre){
    	ans[x]=t[x]?K+1-f[x]:f[x];
    	for(size_t i=0;i<g[x].size();i++){
    		if(g[x][i]==pre)continue;
    		t[g[x][i]]=t[x]^dir[g[x][i]];
    		getans(g[x][i],x);
    	}
    }
    
    int main()
    {
    	cin >> n >> m;
    	for(int i=1;i<n;i++){
    		int u,v;scanf("%d%d",&u,&v);
    		adde(u,v),adde(v,u);
    	}
    	dfs(1,0);
    	for(int i=1;i<=m;i++){
    		int u,v;scanf("%d%d",&u,&v);
    		perform(u,v);
    	}
    	pref(1,0);
    	int l=1,r=n;
    	while(l<r){
    		int mid = (l+r)>>1;
    		if(check(mid))r=mid;
    		else l=mid+1;
    	}
    	cout << l << endl;
    	check(l);
    	getans(1,0);
    	for(int i=1;i<=n;i++)printf("%d ",ans[i]);
    	puts("");return 0;
    }
    
  • 相关阅读:
    PHP压缩html网页代码 : 清除空格,制表符,注释标记
    CentOS 编译 Nginx 服务
    Fedora 下安装Fcitx输入法
    SVN 脚本
    Linux 在线播放
    Linux命令行下常用svn命令
    linux vi(vim)常用命令汇总
    MySQL修改root密码
    Fedora 查看CHM帮助文档
    Fedora 快捷键
  • 原文地址:https://www.cnblogs.com/weiyanpeng/p/12584863.html
Copyright © 2020-2023  润新知