Gym-101615D Rainbow Roads 树的DFS序 差分数组
题目链接:https://cn.vjudge.net/problem/Gym-101615D
题意
给一棵树,每个边权表示一种颜色。
现定义一条彩虹路是每个颜色不相邻的路。
一个好点是所有从该节点开始的所有简单路径(最短路)都是彩虹路。
问有哪几个好点?按编号输出。
思路
按节点遍历,若有多条路边权一样,则这几个子树都不是好点。
除去不好点,剩下即为好点。
一开始的思路是树上dp,然而情况实在太多,WA好几次。
最后看题解,发现有个dfs序的操作,把子树表示成数组里的一个范围,每次区间打标志即可(差分数组)。
提交过程
| WA×n | 树形dp |
| AC |
代码
#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=5e4+20, maxm=maxn*2;
struct Edge{
int to, nxt, val;
Edge(int to=0, int nxt=0, int val=0):
to(to), nxt(nxt), val(val) {}
}edges[maxm];
int head[maxn], esize;
int tim, st[maxn], siz[maxn], fa[maxn], dfn[maxn];
int n;
void init(void){
memset(head, -1, sizeof(head));
esize=0, tim=0;
}
void addEdge(int from, int to, int val){
edges[esize]=Edge(to, head[from], val);
head[from]=esize++;
}
void dfs(int u, int pre){
dfn[tim]=u;
st[u]=tim++; siz[u]=1; fa[u]=pre;
#define TO edges[i].to
for (int i=head[u]; i!=-1; i=edges[i].nxt)
if (TO!=pre) dfs(TO, u), siz[u]+=siz[TO];
#undef TO
}
int main(void){
int a, b, val;
while (scanf("%d", &n)==1){
init();
for (int i=0; i<n-1; i++){
scanf("%d%d%d", &a, &b, &val);
addEdge(a, b, val);
addEdge(b, a, val);
}
dfs(1, -1);
int diff[maxn]={0};
for (int u=1; u<=n; u++){
vector<pair<int, int> > e;
for (int i=head[u]; i!=-1; i=edges[i].nxt)
e.push_back(make_pair(edges[i].val, edges[i].to));
sort(e.begin(), e.end());
int ptr=0, sizes=e.size();
while (ptr<sizes){
int pre=e[ptr].first, tmp=ptr+1;
while (tmp<sizes && pre==e[tmp].first) tmp++;
if (tmp-1==ptr) {ptr++; continue;}
if (pre!=e[tmp-1].first) break;
for (; ptr<=tmp-1; ptr++){
int to=e[ptr].second;
// printf("%d: %d st%d siz%d\n", u, to, st[to], siz[to]);
if (to==fa[u]){
diff[st[1]]++;
diff[st[u]]--;
diff[st[u]+siz[u]]++;
}else{
diff[st[to]]++;
diff[st[to]+siz[to]]--;
}
}
}
}
for (int i=1; i<=n; i++)
diff[i]+=diff[i-1];
int ans[maxn], asize=0;
for (int i=1; i<=n; i++)
if (diff[st[i]]==0) ans[asize++]=i;
// for (int i=1; i<=n; i++)
// printf("%d: %d siz%d\n", i, st[i], siz[i]);
printf("%d\n", asize);
for (int i=0; i<asize; i++)
printf("%d\n", ans[i]);
}
return 0;
}
| Time | Memory | Length | Lang | Submitted |
|---|---|---|---|---|
| 62ms | 4876kB | 2466 | GNU G++ 5.1.0 | 2018-08-30 20:57:26 |
Gym-101615D Rainbow Roads 树的DFS序 差分数组的更多相关文章
- [2]树的DFS序
定义: 树的DFS序就是在对树进行DFS的时候,对树的节点进行重新编号:DFS序有一个很强的性质: 一颗子树的所有节点在DFS序内是连续的一段, 利用这个性质我们可以解决很多问题. 代码: void ...
- 树的dfs序 && 系统栈 && c++ rope
利用树的dfs序解决问题: 就是dfs的时候记录每个节点的进入时间和离开时间,这样一个完整的区间就是一颗完整的树,就转化成了区间维护的问题. 比如hdu3887 本质上是一个求子树和的问题 #incl ...
- CF877E Danil and a Part-time Job 线段树维护dfs序
\(\color{#0066ff}{题目描述}\) 有一棵 n 个点的树,根结点为 1 号点,每个点的权值都是 1 或 0 共有 m 次操作,操作分为两种 get 询问一个点 x 的子树里有多少个 1 ...
- HDU4117 GRE WORDS(AC自动机+线段树维护fail树的dfs序)
Recently George is preparing for the Graduate Record Examinations (GRE for short). Obviously the mos ...
- 【枚举】【DFS序】Gym - 101617G - Rainbow Roads
题意:一颗树,每条边有个颜色,一条路径被定义为“彩虹”,当且仅当其上没有长度大于等于2的同色子路径.一个结点被定义为“超级结点”,当且仅当从其发出的所有路径都是“彩虹”. 枚举所有长度为2,且同色的路 ...
- bzoj 3551 [ONTAK2010]Peaks加强版(kruskal,主席树,dfs序)
Description [题目描述]同3545 Input 第一行三个数N,M,Q. 第二行N个数,第i个数为h_i 接下来M行,每行3个数a b c,表示从a到b有一条困难值为c的双向路径. 接下来 ...
- 2018.11.01 NOIP训练 图论(线段树+倍增+dfs序)
传送门 一道挺妙的题. 对于询问点(u,v),如右图所示,我们可以发现存在一个点m在u->v的路径中,m子树的点到u是最近的,m子树外到v是最近的.其中dis(u,m)=(dis(u,v)-1) ...
- 线段树(dfs序建树加区间更新和单点查询)
题目链接:https://cn.vjudge.net/contest/66989#problem/J 记录一下这道折磨了我一天的题,.... 具体思路: 具体关系可通过dfs序建树,但是注意,在更新以 ...
- bzoj3306: 树(dfs序+倍增+线段树)
比较傻逼的一道题... 显然求子树最小值就是求出dfs序用线段树维护嘛 换根的时候树的形态不会改变,所以我们可以根据相对于根的位置分类讨论. 如果询问的x是根就直接输出整棵树的最小值. 如果询问的x是 ...
随机推荐
- redis安装配置-linux
wget http://download.redis.io/releases/redis-3.2.9.tar.gz .tar.gz cd redis-/ make --启动 ./redis-serve ...
- POJ 2831
次小生成树.求出两点间最短路径的最大权值,再把要加入的边与之比较即可. #include <iostream> #include <cstdio> #include <c ...
- Android Studio怎样删除module
当你想在Android Studio中删除某个module时,大家习惯性的做法都是选中要删除的module.右键去找delete.可是 在Android Studio中你选中module,右键会发现没 ...
- structs实现三种action的方法
第一种:一般类,带有public String execute()方法. 另外一种:继承LoginActionInterface implements Action接口的类. 第三种:继承LoginA ...
- 【c语言】数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字
题目:数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字. 比如输入一个长度为9的数组{1,2.3.2,2.2.5,4.2}, 因为数组中数字2出现了5次,超过数组的长度的一半,因此输出2 ...
- Vue环境搭建+VSCode+Win10
一.安装Node.js(js的运行环境) 1.在Node.js官网https://nodejs.org/en/download/下载安装包.2.下载后进行安装.3.打开命令行,输入node -v可以查 ...
- w3school
http://www.runoob.com/w3cnote_genre/android https://www.tutorialspoint.com/android/android_sqlite_da ...
- JavaScript:目录
ylbtech-JavaScript:目录 1. https://www.javascript.com/ 2. 1.返回顶部 1. http://www.runoob.com/js/js-functi ...
- 11.修改WSDL文档
http://localhost:8077/person?wsdl可以由你来控制的.拿Person这个例子来说.
- Codeforces Round #512 (Div. 2) D.Vasya and Triangle 数学
题面 题意:给你n,m,k,在你在(0,0)到(n,m)的矩形内,选3个格点(x,y都是整数),使得三角形面积为n*m/k,不能找到则输出-1 题解:由毕克定理知道,格点多边形的面积必为1/2的整数倍 ...