2019ACM/CCPC吉林省赛——B.Gift Node【DFS+差分约束】

B Gift Node

Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 524288/524288K (Java/Other)

Problem Description

You are given a tree with n nodes (numbered from 1 to n). The root is node 1. Each edge in this tree has a particular color which is specified by an integer from 1 to 10^8. We define a path on the tree as a gift path if and only if adjacent edges on the path have different colors. In addition, we define a node as a gift node, if all the paths starting at this node are gift paths.

We have Q questions for you. For each question, you are given a node R, and you need to find out the number of gift nodes in the subtree of node R. Note that when we say a node in some subtree is a gift node, only paths in that subtree will be considered.

Input

First line contains an integer n(1≤n≤200000).
Each of the next n-1 lines contains three integers 1≤Ai,Bi,Ci(Ai,Bi,Ci≤n,Ai≠Bi) , represents an edge of color Ci that connects nodes Ai and Bi.
Then there will be a line which contains a single integer Q(1≤Q≤10000), represents the number of questions.
Each of the next Q lines contains a single integer Ri(1≤Ri≤n), we want to know the number of gift nodes in the subtree where the root is Ri.

Output

Print Q lines, each line contains a single integer Si, represents the answer for question i.

Sample Input

8
1 3 1
2 3 1
3 4 3
4 5 4
5 6 3
6 7 2
6 8 2
2
1
5

Sample Output

4
2

Hint

In the first question, the gift nodes are 3,4 ,5 and 6.

In the second question, the gift nodes are 5 and 6.

题意:

如果一条路径上所有相邻边都不相等,那么这条路径叫做礼物路径;

如果一个点的子树中所有路径都为礼物路径,那么这个点叫做礼物节点;

题目给出q个询问,每个询问给出一个数k,求k的子树中有多少个礼物节点。

分析:

场上读错题,写了假的算法结果wa13发,疯狂查错没想到是读错题的锅。

这篇题解可能不够成熟,理解可能不够透彻,我尽量把自己的想法讲清楚。【谢谢春燕大佬教我%%%】

受大佬启发,想到了差分约束,类似转化成线段树或树状数组的做法,跑一遍dfs序到相应的timer,那么节点i的l[i]和r[i]就可以抽象成一段区间,然后对该区间做差分约束。

【不懂差分约束的可以看看一道洛谷入门题目 P1047 校门外的树】

dfs序之后,我们就将子树抽象成了很多段区间,按照差分约束的思想,就是根据情况对区间打标记,也就是对区间两端标记,在这里我做的标记是该区间(即该子树)是否有非礼物路径,也就是说是否存在相邻边相等的情况,如果有就做标记,那么最后只需要处理前缀和后看有多少个没有标记,就是答案所求的某点子树中礼物节点的个数。

差分约束的具体做法是:将每个点的边按照边权排序,这样处理的时候那么边权相等的边就可以前后处理,不需要扫一遍;a,b是当前扫到需要判断的边,如果权值相等就继续向后枚举b,否则将a更新为b,继续枚举直到结束;u,v是a,b这两条边连接的端点(另一个端点是当前枚举的点i),如果u(或v)是当前i点的父节点,那么非礼物路径只影响除i的子树外的部分,如果不是父节点,那么只影响u(或v)的子树而不影响别的部分,按照这四种情况分别差分约束做标记。

结束差分约束后记cnt的前缀和【联系差分约束的思想】,如果!cnt[i](未标记),就表示当前不存在非礼物路径,那么当前就是一个礼物节点,从而更新ans数组,当前的ans[i]只记录i点是不是礼物节点,然后再跑一遍dfs,ans更新为i的子树中礼物节点的个数。

#include
#define pb push_back
using namespace std;
const int maxn=2e5+7;
struct node{int to,w;};
vector g[maxn];
int cnt[maxn],pre[maxn],l[maxn],r[maxn],ans[maxn];
int n,timer,m;
bool cmp(node a,node b) {return a.w

 

你可能感兴趣的:(ACM/ICPC,搜索,DFS)