题目传送门

题目大意:

给出一颗树,每条边都有一个颜色,对一个点来说,如果其他所有点到这个点的简单路径,相连的边颜色都不同,这个点即合法点,统计所有的合法点。

思路:

对于一个节点来说

1、如果这个节点的两个子节点的边颜色一样,那么这两个子节点的子树都要放弃。

2、如果这个节点的子节点和他的父节点的边的颜色一样,那么子节点所在子树放弃,父节点中除了这个节点以外的其他节点都要放弃。

剩下的点就是合法点。

那怎么做到放弃呢?

先dfs处理出每个节点的dfs序,每个dfs序对应的节点标号,每个节点的子树大小(包括本身),对于第一种情况来说,dfs序在  子树节点dfs序  到 子树节点dfs序加上子树大小  这个左闭右开的区间都要放弃,则用一个数组,左边界加一,右边界减一。

对于第二种情况,放弃的子节点和上述一样处理,父节点就要放弃  dfs序从1到父节点dfs序,父节点dfs序+1到最后所有的点,则对应位置加一或者减一,最后vis[ i ]=vis[ i  -1 ] + arr[ i ].处理完后,vis还等于0的点,就是合法的dfs序,找到这个dfs序对应的节点就可以了(dfs的时候就记录过了,大佬说这个做法叫差分约束)。

这题五万个点,每个点三个数据,用读入优化居然没有快,,,可能是我的读入优化还不够优秀吧。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<string.h>
#include<sstream>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<stack>
#include<bitset>
#define CLR(a,b) memset((a),(b),sizeof((a)))
using namespace std;
typedef long long ll;
inline int rd() {
int f = 1; int x = 0; char s = getchar();
while (s<'0' || s>'9') { if (s == '-')f = -1; s = getchar(); }
while (s >= '0'&&s <= '9') { x = x * 10 + s - '0'; s = getchar(); }x *= f;
return x;
}
int n;
struct edge {
int v, color;
edge(){}
edge(int v,int color): v(v),color(color){} };
bool cmp(edge &a, edge &b)
{
return a.color < b.color;
}
const int maxn = 50010;
vector<edge >g[maxn];
int arr[maxn], fa[maxn], son[maxn], dfn[maxn],tot,cnt,vis[maxn],dir[maxn];
void dfs(int u, int pre)
{
fa[u] = pre;
son[u] = 1;
dfn[u] = ++cnt;
dir[cnt] = u;
for (auto it : g[u])
{
if (it.v == pre)continue;
dfs(it.v, u);
son[u] += son[it.v];
}
}
int main() {
cin >> n;
for (int i = 1; i < n; i++)
{
int u, v, color;
u = rd(), v = rd(), color = rd();
//scanf("%d%d%d", &u, &v, &color);
g[u].push_back(edge(v, color));
g[v].push_back(edge(u, color));
}
dfs(1, 0);
for (int i = 1; i <= n; i++)
{
sort(g[i].begin(), g[i].end(), cmp);
int si = g[i].size();
for (int j = 0; j < si - 1; j++)
{
if (g[i][j].color == g[i][j + 1].color)
{ int x = g[i][j].v, y = g[i][j+1].v;
if (fa[x] == i && fa[y] == i)
{ arr[dfn[x]]++;
arr[dfn[x] + son[x]]--;
arr[dfn[y]]++;
arr[dfn[y] + son[y]]--;
}
else if (fa[x] == i && fa[i] == y)
{ arr[dfn[x]]++;
arr[dfn[x] + son[x]]--;
arr[dfn[1]]++;
arr[dfn[i]]--;
arr[dfn[i] + son[i]]++;
}
else if (fa[y] == i && fa[i] == x)
{
swap(x, y);
arr[dfn[x]]++;
arr[dfn[x] + son[x]]--;
arr[dfn[1]]++;
arr[dfn[i]]--;
arr[dfn[i] + son[i]]++;
}
}
}
}
for (int i = 1; i <= n; i++)
{
vis[i] = vis[i - 1] + arr[i];
}
vector<int >ans;
for (int i = 1; i <= n; i++)
{
if (vis[i] == 0)
{
tot++;
ans.push_back(dir[i]);
}
}
printf("%d\n", tot);
sort(ans.begin(), ans.end());
for (auto it : ans)
{
printf("%d\n", it);
}
}

  

Gym - 101615 D Rainbow Roads dfs序的更多相关文章

  1. Gym - 101875I I Will Go (dfs序)

    题意:N个人要参加一个局,每个人有自己的好朋友,如果他的好朋友来,他才有可能来.N个人的关系不够成环.Q次查询,问若x来了,y是否肯定来. 分析:若点y是x的祖先,则y肯定回来.一次dfs确定每个点覆 ...

  2. 【枚举】【DFS序】Gym - 101617G - Rainbow Roads

    题意:一颗树,每条边有个颜色,一条路径被定义为“彩虹”,当且仅当其上没有长度大于等于2的同色子路径.一个结点被定义为“超级结点”,当且仅当从其发出的所有路径都是“彩虹”. 枚举所有长度为2,且同色的路 ...

  3. Gym-101615D Rainbow Roads 树的DFS序 差分数组

    题目链接:https://cn.vjudge.net/problem/Gym-101615D 题意 给一棵树,每个边权表示一种颜色. 现定义一条彩虹路是每个颜色不相邻的路. 一个好点是所有从该节点开始 ...

  4. K. Random Numbers(Gym 101466K + 线段树 + dfs序 + 快速幂 + 唯一分解)

    题目链接:http://codeforces.com/gym/101466/problem/K 题目: 题意: 给你一棵有n个节点的树,根节点始终为0,有两种操作: 1.RAND:查询以u为根节点的子 ...

  5. Codeforces Gym 101142 G Gangsters in Central City (lca+dfs序+树状数组+set)

    题意: 树的根节点为水源,编号为 1 .给定编号为 2, 3, 4, …, n 的点的父节点.已知只有叶子节点都是房子. 有 q 个操作,每个操作可以是下列两者之一: + v ,表示编号为 v 的房子 ...

  6. Random Numbers Gym - 101466K dfs序+线段树

    Tamref love random numbers, but he hates recurrent relations, Tamref thinks that mainstream random g ...

  7. Gym 101142G : Gangsters in Central City(DFS序+LCA+set)

    题意:现在有一棵树,1号节点是水源,叶子节点是村庄,现在有些怪兽会占领一些村庄(即只占领叶子节点),现在要割去一些边,使得怪兽到不了水源.给出怪兽占领和离开的情况,现在要割每次回答最小的割,使得怪兽不 ...

  8. cdoj 574 High-level ancients dfs序+线段树

    High-level ancients Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.uestc.edu.cn/#/problem/s ...

  9. BZOJ 3011: [Usaco2012 Dec]Running Away From the Barn( dfs序 + 主席树 )

    子树操作, dfs序即可.然后计算<=L就直接在可持久化线段树上查询 -------------------------------------------------------------- ...

随机推荐

  1. mysql case

    1.table CREATE TABLE `lee`(`id` INT(10) NOT NULL auto_increment,`name` varchar(20) DEFAULT null,`bir ...

  2. C++之deque

    deque(包含头文件#include<deque>)由若干段连续空间串接而成,一旦有必要在deque的头部或尾端增加新的空间,便配置一段定量连续的空间,串接在deque的头部或尾端.de ...

  3. elasticsearch2.x ik插件

    先来一个标准分词(standard),配置如下: curl -XPUT localhost:/local -d '{ "settings" : { "analysis&q ...

  4. 常用linux配置文件

    /etc/hosts:用户IP与域名的对应解析表/etc/sysconfig/network:机器名.网卡启动.网关等配置/etc/fstab:记录开机自动挂载的文件系统/etc/rc.local:开 ...

  5. linux中怎么结果一页一页输出

    比如sudo apt-cache search php 结果可能有两个屏幕,但是命令执行完毕之后直接就跳到最后面了,我想看第一行怎么办? 可以用管道命令(|)把一个命令的结果作为另一个命令的参数即可. ...

  6. 自定义MVC的Helper扩展方法 转 Insus.NET

    记得在开发ASP.NET时候,也经常性使用C#可以写自己义的扩展方法,如: http://www.cnblogs.com/insus/p/3154363.html 或http://www.cnblog ...

  7. Xshell连接不上Linux的解决方法

    xshell连接linux主机时,会出现错误:Could not connect to '127.0.0.1' (port 22): Connection failed.  但是这时能ping通. 通 ...

  8. java代理模式实例讲解

    下面这个是设计模式课上的例子: import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import ...

  9. MySQL的ODBC安装错误问题!

    MySQL的ODBC安装时候可能会出错,主要原因是缺少VC支持库,需要2010版本的VC支持库!!X86和X64分别对应MySQL对应的ODBC,不能安装一个两个都搞定,如果需要安装两个ODBC驱动, ...

  10. [51nod1222] 最小公倍数计数(莫比乌斯反演)

    题面 传送门 题解 我此生可能注定要和反演过不去了--死都看不出来为啥它会突然繁衍反演起来啊-- 设\(f(n)=\sum_{i=1}^n\sum_{j=1}^n[{ij\over\gcd(i,j)} ...