题目链接

\(Description\)

给定两棵\(n\)个点的树,分别是由\(n-1\)条蓝边和\(n-1\)条红边组成的树。求\(n-1\)次操作后,能否把蓝树变成红树。

每次操作是,选择当前树上一条只由蓝边组成的简单路径\(u\to v\),删掉路径上的任意一条蓝边,然后在路径上任选两个点,在这两个点之间加一条红边。

\(n\leq10^5\)。

\(Solution\)

模拟一下样例二,就比较容易想到:

考虑能否从红树变回到蓝树。

我们每次要找到当前树上一条蓝边组成的路径\(u\to v\),设路径上任意一点是\(a\),不在路径上的一个点是\(b\)。如果当前\(a,b\)之间有红边相连,而\(b\)与路径上某点\(c\)在蓝树上有边,显然这条红边\((a,b)\)是可以通过删掉\((b,c)\)加入的,也就是现在我们在当前树上删掉边\((a,b)\),加入边\((b,c)\)。然后继续找蓝边路径继续扩展。

怎么实现这一过程呢?

对于整条蓝边组成的路径\(u\to v\),我们不需要管具体有哪些点,只需要知道\(b\)与\(u\to v\)之间既有一条红边,也有一条蓝边(不会有两条红边/蓝边啊,因为每次操作后也是一棵树),然后我们可以删掉这条红边,加入这条蓝边。边具体是哪条也不需要管,我们只需要知道\(b\)被加入了路径\(u\to v\)。

所以就可以用并查集实现。\(b\)被合并到路径\(u\to v\)前,要把与\(b\)相连的所有边连到路径\(u\to v\)(的代表点)上去,可以用启发式合并。

同时有红边和蓝边与路径相连,就是这条边出现了两次。所以我们把出现两次的边拿出来扩展就好了。

能扩展\(n-1\)次则可行,否则不行。

启发式合并然后用set维护出边,复杂度\(O(n\log^2n)\)。出边可以hash点对\((u,v)\)来维护,少一个\(\log\),懒得写了。。

//287ms	25472KB
#include <set>
#include <cstdio>
#include <cctype>
#include <algorithm>
#define gc() getchar()
typedef long long LL;
const int N=1e5+5; int fa[N];
std::set<int> st[N];
std::pair<int,int> q[N]; inline int read()
{
int now=0;register char c=gc();
for(;!isdigit(c);c=gc());
for(;isdigit(c);now=now*10+c-'0',c=gc());
return now;
}
int Find(int x)
{
return x==fa[x]?x:fa[x]=Find(fa[x]);
} int main()
{
const int n=read();
int h=0,t=0;
for(int i=n-1<<1; i; --i)
{
int u=read(),v=read();
// if(u>v) std::swap(u,v);
if(!st[u].count(v)) st[u].insert(v), st[v].insert(u);
else q[t++]=std::make_pair(u,v);
}
for(int i=1; i<=n; ++i) fa[i]=i;
while(h<t)
{
int x=Find(q[h].first),y=Find(q[h++].second);
if(st[x].size()<st[y].size()) std::swap(x,y);//x<-y
for(std::set<int>::iterator it=st[y].begin(); it!=st[y].end(); ++it)
if(*it!=x)
{
int u=x,v=*it;
st[v].erase(y);
// if(u>v) std::swap(u,v);
if(!st[u].count(v)) st[u].insert(v), st[v].insert(u);
else q[t++]=std::make_pair(u,v);
}
st[x].erase(y), fa[y]=x;
}
puts(t==n-1?"YES":"NO"); return 0;
}

AGC 014E.Blue and Red Tree(思路 启发式合并)的更多相关文章

  1. AT2377 Blue and Red Tree

    AT2377 Blue and Red Tree 法一:正推 红色的边在蓝色的树上覆盖,一定每次选择的是覆盖次数为1的边的覆盖这条边的红色边连出来 覆盖次数可以树剖找到 这条红色边,可以开始的时候每个 ...

  2. AtCoder AGC014E Blue and Red Tree (启发式合并)

    题目链接 https://atcoder.jp/contests/agc014/tasks/agc014_e 题解 完了考场上树剖做法都没想到是不是可以退役了... 首先有一个巨难写的据说是\(O(n ...

  3. AGC014E Blue and Red Tree

    题意 There is a tree with \(N\) vertices numbered \(1\) through \(N\). The \(i\)-th of the \(N−1\) edg ...

  4. AtCoder Grand Contest 014 E:Blue and Red Tree

    题目传送门:https://agc014.contest.atcoder.jp/tasks/agc014_e 题目翻译 有一棵有\(N\)个点的树,初始时每条边都是蓝色的,每次你可以选择一条由蓝色边构 ...

  5. 【AGC014E】Blue and Red Tree

    Description 给定一棵\(n\)个节点的蓝边树,再给定一棵\(n\)个节点的红边树.请通过若干次操作将蓝树变成红树.操作要求和过程如下: 1.选定一条边全为蓝色的路径: 2.将路径上的一条蓝 ...

  6. [AT2377] [agc014_e] Blue and Red Tree

    题目链接 AtCoder:https://agc014.contest.atcoder.jp/tasks/agc014_e 洛谷:https://www.luogu.org/problemnew/sh ...

  7. [atAGC014E]Blue and Red Tree

    不断删除重边,然后将两个点的边集启发式合并(要考虑到两棵树),合并时发现重边就加入队列,最后判断是否全部删完即可 1 #include<bits/stdc++.h> 2 using nam ...

  8. dsu on tree 树上启发式合并 学习笔记

    近几天跟着dreagonm大佬学习了\(dsu\ on\ tree\),来总结一下: \(dsu\ on\ tree\),也就是树上启发式合并,是用来处理一类离线的树上询问问题(比如子树内的颜色种数) ...

  9. dsu on tree[树上启发式合并学习笔记]

    dsu on tree 本质上是一个 启发式合并 复杂度 \(O(n\log n)\) 不支持修改 只能支持子树统计 不能支持链上统计- 先跑一遍树剖的dfs1 搞出来轻重儿子- 求每个节点的子树上有 ...

随机推荐

  1. 005-2-Python文件操作

    Python文件操作(file) 文件操作的步骤: 打开文件,得到文件句柄并赋值给一个变量 通过句柄对文件进行操作 关闭文件(操作文件后记住关闭) 1.读写文件的基础语法: open() 将会返回一个 ...

  2. openmp查看最大线程数量

    CMakeLists.txt cmake_minimum_required(VERSION 2.8) project(omp_test) find_package(OpenMP REQUIRED) i ...

  3. 【C++ Primer 第13章】2. 拷贝控制和资源管理

    拷贝控制和资源管理 • 类的行为像一个值.意味着它应该有自己的状态,当我们拷贝一个像值得对象时,副本和原对象是完全独立的,改变副本不会对原对象有任何影响. • 行为像指针的类则共享状态.当我们拷贝一个 ...

  4. python安装plinter

    我下的python2.7是有pip的,但是直接在cmd中输入pip是无响应的.要去环境变量中配置D:/python/Script 这样就可以了. pip install splinter就能下载了

  5. python__int 部分内部功能介绍

    查看创建的对象的类型: age=18 print(type(age)) 结果: <class 'int'> x.bit_length():返回二进制的位数 Python中进制的转换: Py ...

  6. Codeforces 1017F The Neutral Zone (看题解)

    这题一看就筛质数就好啦, 可是这怎么筛啊, 一看题解, 怎么会有这么骚的操作. #include<bits/stdc++.h> #define LL long long #define f ...

  7. JQuery函数大全

    $(”p”).addClass(css中定义的样式类型); 给某个元素添加样式 $(”img”).attr({src:”test.jpg”,alt:”test Image”}); 给某个元素添加属性/ ...

  8. 51Nod1766 树上的最远点对 ST表 LCA 线段树

    原文链接https://www.cnblogs.com/zhouzhendong/p/51Nod1766.html 题目传送门 - 51Nod1766 题意 n个点被n-1条边连接成了一颗树,给出a~ ...

  9. Hadoop| MapReduce01 概述

    概述 分布式运算程序: 优点:易于编程:良好扩展性:高容错性:适合PB级以上海量数据的离线处理: 缺点:不擅长实时计算:不擅长流式计算:不擅长DAG有向图计算: 核心思想: 1)分布式的运算程序往往需 ...

  10. JAVA 关键字及其作用解释

    1. 访问控制 1) private 私有的 private 关键字是访问控制修饰符,可以应用于类.方法或字段(在类中声明的变量). 只能在声明 private(内部)类.方法或字段的类中引用这些类. ...