题目传送门

题目大意:

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

思路:

对于一个节点来说

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. 浅谈Android四大组建之一Service---Service与Activity的绑定

    从上一篇文章我们学会了如何创建Service,我们通过监听一个按钮,然后再按钮里面通过意图来启动Service.但是我们有没有发现,启动服务以后,Activity和Service之间的联系好像就断开了 ...

  2. 使用ffmpeg转换视频格式

    命令: ffmpeg -i infile -ab 128 -acodec libmp3lame -ac 1 -ar 22050 -r 29.97 -qscale 6 -y outfile   说明: ...

  3. 【总结整理】openlayer

    实时路况 http://www.cnblogs.com/gisvip/archive/2012/11/24/2787141.html

  4. 洛谷P3328(bzoj 4085)毒瘤线段树

    题面及大致思路:https://www.cnblogs.com/Yangrui-Blog/p/9623294.html, https://www.cnblogs.com/New-Godess/p/45 ...

  5. Codeforces 1108F (MST Unification) (树上倍增 or 改进 kruksal)

    题意:给你一张n个节点和m条边的无向连通图, 你可以执行很多次操作,对某一条边的权值+1(对于每条边,可以不加,可以无限次加),问至少进行多少次操作,可以使这张图的最小生成树变得唯一,并且最小生成树的 ...

  6. Codeforces 1077E (二分乱搞或者dp)

    题意:给你一个数组,可以从中选区若干种元素,但每种元素选区的个数前一种必须是后一种的2倍,选区的任意2种元素不能相同,问可以选取最多的元素个数是多少? 思路1(乱搞):记录一下每种元素的个数,然后暴力 ...

  7. 算法Sedgewick第四版-第1章基础-1.4 Analysis of Algorithms-006BitonicMax

    package algorithms.analysis14; import algorithms.util.StdOut; import algorithms.util.StdRandom; /*** ...

  8. Luogu 3479 [POI2009]GAS-Fire Extinguishers

    补上了这一道原题,感觉弱化版的要简单好多. 神贪心: 我们设$cov_{x, i}$表示在$x$的子树中与$x$距离为$i$的还没有被覆盖到的结点个数,设$rem_{x, i}$表示在$x$的子树中与 ...

  9. 数据结构_Summary

    问题描述 可怜的 Bibi 丢了好几台手机以后,看谁都像是小偷,他已经在小本本上记下了他认为的各个地点的小偷数量.现在我们将 Bibi 的家附近的地形抽象成一棵有根树. 每个地点都是树上的一个节点,节 ...

  10. WordCountPro 编码与测试

    WordCountPro github项目地址:https://github.com/handsomesnail/WordCountPro PSP表格 PSP2.1  PSP阶段  预估耗时(小时) ...