zoukankan      html  css  js  c++  java
  • AtCoder Grand Contest 014 E:Blue and Red Tree

    题目传送门:https://agc014.contest.atcoder.jp/tasks/agc014_e

    题目翻译

    有一棵有(N)个点的树,初始时每条边都是蓝色的,每次你可以选择一条由蓝色边构成的简单路径,让这条路径的两个端点间连上一条红边,然后断开这条路径上的某条蓝边。这样做(N-1)次,就可以把原本的蓝树变成红树。现在给你蓝树和红树的样子,问你可不可能把给出的蓝树变成给出的红树。(Nleqslant 10^5)

    题解

    先膜一发大佬的题解:https://blog.csdn.net/sadnohappy/article/details/79478193

    也许是昨天状态不好……想了一下午都想不出……就去看题解了……

    思路想到一半卡住了,看了题解的最后一步思路之后不知道怎么实现,我觉得我还是太菜了。

    先讲讲我一个(O(N^2logn))的暴力吧:

    因为每次连红边都要保证两点之间有一条完全由蓝边构成的简单路径,然后断开某条蓝边。所以我们把所有路径都丢到树上去差分一下,然后求出每条边被多少条路径覆盖,每次把只被覆盖一次的蓝边断开,然后把那一条唯一的覆盖它的红边的差分影响消去,更新一下差分值。这样子如果做不了(N-1)次就是(NO),否则(YES)

    顺着这个思路往下想,既然我可以知道顺着怎么一条一条边断开,我当然也可以知道逆着怎么一条一条边接上来。然后我自己就想不出接下来该怎么办了。

    因为最后一条断开的边肯定是红蓝都一样的,那么我假设这个蓝边一开始就不存在,然后把这条蓝边链接的两个点合成一个点,把所有边的信息都更新一下,我们会发现接下来删的蓝边应该也会存在一条红边对应。这样做(N-1)次就行了。因为我是倒着做的,所以之前被我印点的断开的边在现在被我选中的路径上还是连上的。

    至于实现,看代码吧……我基本不用(stl)的……但是我真的不知道还有什么别的实现方法……

    时间复杂度:(O(NlogN))

    空间复杂度:(O(N)xinxi)

    代码如下:

    #include <set>
    #include <map>
    #include <queue>
    #include <cstdio>
    #include <algorithm>
    using namespace std;
    typedef pair<int,int> pii;
    
    const int maxn=1e5+5;
    
    int n;
    int fa[maxn];
    queue<pii> q;
    set<int>s[maxn];
    map<pii,int>cnt;
    set<int>::iterator it;
    
    int read() {
    	int x=0,f=1;char ch=getchar();
    	for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
    	for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
    	return x*f;
    }
    
    int find(int x) {
    	if(fa[x]==x)return x;
    	return fa[x]=find(fa[x]);
    }
    
    int main() {
    	n=read();
    	for(int i=1;i<2*n-1;i++) {
    		int x=read(),y=read();
    		s[x].insert(y),s[y].insert(x);
    		if(x>y)swap(x,y);
    		pii tmp=make_pair(x,y);
    		cnt[tmp]++;
    		if(cnt[tmp]==2)q.push(tmp);
    	}
    	for(int i=1;i<=n;i++)fa[i]=i;
    	for(int i=1;i<n;i++) {
    		if(q.empty()) {puts("NO");return 0;}
    		int x=0,y=0;
    		for(;x==y;x=find(q.front().first),y=find(q.front().second),q.pop());
    		if(s[x].size()>s[y].size())swap(x,y);fa[x]=y;//启发式合并,保证每条边最多被合并logn次
    		for(it=s[x].begin();it!=s[x].end();it++) {
    			int v=*s[x].find(*it);
    			s[v].erase(s[v].find(x));
    			if(v==y)continue;
    			s[v].insert(y),s[y].insert(v);
    			pii tmp;
    			if(v>y)tmp=make_pair(y,v);
    			else tmp=make_pair(v,y);
    			cnt[tmp]++;
    			if(cnt[tmp]==2)q.push(tmp);
    		}//更新边的信息
    	}
    	puts("YES");
    	return 0;
    }
    
  • 相关阅读:
    ios in-house 公布整个过程(startssl认证)
    各种图的创建以及广度,深度优先遍历(临接矩阵存储)
    SWTBOK測试实践系列(1) -- 測试在项眼下期的评审投入划算吗?
    欢天喜地迎国庆,国产开源编程语言 RPP 1.87 公布!
    正确地在QML应用中使用fontsize
    iOS 9音频应用播放音频之第一个ios9音频实例
    iOS 9音频应用播放音频之ios9音频基本功能
    iOS 9音频应用开发基础教程
    MAC OS 10.11.1虚拟机免费下载已安装Xcode7图片后有下载地址
    检验Xcode是否被改动过的简单方法,不妨试试!!!
  • 原文地址:https://www.cnblogs.com/AKMer/p/10030259.html
Copyright © 2011-2022 走看看