解题报告——树形结构

比较水的题就不放了。

1、

After the piece of a devilish mirror hit the Kay's eye, he is no longer interested in the beauty of the roses. Now he likes to watch snowflakes.

Once upon a time, he found a huge snowflake that has a form of the tree (connected acyclic graph) consisting of n nodes. The root of tree has index 1. Kay is very interested in the structure of this tree.

After doing some research he formed q queries he is interested in. The i-th query asks to find a centroid of the subtree of the node vi. Your goal is to answer all queries.

Subtree of a node is a part of tree consisting of this node and all it's descendants (direct or not). In other words, subtree of node v is formed by nodes u, such that node v is present on the path from u to root.

Centroid of a tree (or a subtree) is a node, such that if we erase it from the tree, the maximum size of the connected component will be at least two times smaller than the size of the initial tree (or a subtree).

Input

The first line of the input contains two integers n and q (2 ≤ n ≤ 300 000, 1 ≤ q ≤ 300 000) — the size of the initial tree and the number of queries respectively.

The second line contains n - 1 integer p2, p3, ..., pn (1 ≤ pi ≤ n) — the indices of the parents of the nodes from 2 to n. Node 1 is a root of the tree. It's guaranteed that pi define a correct tree.

Each of the following q lines contain a single integer vi (1 ≤ vi ≤ n) — the index of the node, that define the subtree, for which we want to find a centroid.

Output

For each query print the index of a centroid of the corresponding subtree. If there are many suitable nodes, print any of them. It's guaranteed, that each subtree has at least one centroid.

Example

Input

7 4
1 1 3 3 5 3
1
2
3
5

Output

3
2
3
6

这是一道求重心的题,求重心很简单,但是这题要输出每个子树的重心,所以我们在处理由父亲那条边的子树的时候必须有所改变。我们首先不处理这种子树,然后在后面选取重心之后,再向上更新:

 for(int i = head[x]; i; i = nxt[i])
     if(sum[g[i]]*2 > sum[x] && g[i] != fa) ans[x] = ans[g[i]];
    while((sum[x] - sum[ans[x]])*2 > sum[x]) ans[x] = f[ans[x]];

ans【x】是指x的子树中的重心,选出的ans中都没有算出它的x方向的子树,所以我们可以向上跳,直到跳到其重心。

貌似这道题难以用最大子树的大小最小这一定理来做,因为难以处理当前点到父亲的子树的大小。

#include<bits/stdc++.h>
using namespace std;
int cnt, n, m, nxt[200002], head[100002], g[200002], sum = 0;
int dep[100002], cha[100002], fa[100002][22], id[200002], ans[100002];
inline void addedge(int x, int y)
{
    cnt++;
    g[cnt] = y;
    nxt[cnt] = head[x];
    head[x] = cnt;
}
inline void dfs(int x, int father, int dept)
{
    fa[x][0] = father;
    dep[x] = dept;
    for(int i = head[x]; i; i = nxt[i])
    {
        if(g[i] != father){
            dfs(g[i], x, dept+1);
        }
    }
}

int main()
{
    scanf("%d", &n);
    for(int i = 1; i <= n; i++)
       scanf("%d", &a[i]);
    for(int i = 1; i < n; i++)
    {
        int x, y;
        scanf("%d %d", &x, &y);
        addedge(x, y);
        addedge(y, x);
    }
    dfs(1, 0, 1);
    for(int i = 1; i < n; i++)
    printf("%d ", ans[i]);
    return 0;
}

2、

They say that Berland has exactly two problems, fools and roads. Besides, Berland has n cities, populated by the fools and connected by the roads. All Berland roads are bidirectional. As there are many fools in Berland, between each pair of cities there is a path (or else the fools would get upset). Also, between each pair of cities there is no more than one simple path (or else the fools would get lost).

But that is not the end of Berland's special features. In this country fools sometimes visit each other and thus spoil the roads. The fools aren't very smart, so they always use only the simple paths.

A simple path is the path which goes through every Berland city not more than once.

The Berland government knows the paths which the fools use. Help the government count for each road, how many distinct fools can go on it.

Note how the fools' paths are given in the input.

Input

The first line contains a single integer n (2 ≤ n ≤ 105) — the number of cities.

Each of the next n - 1 lines contains two space-separated integers ui, vi (1 ≤ ui, vi ≤ nui ≠ vi), that means that there is a road connecting cities ui and vi.

The next line contains integer k (0 ≤ k ≤ 105) — the number of pairs of fools who visit each other.

Next k lines contain two space-separated numbers. The i-th line (i > 0) contains numbers ai, bi (1 ≤ ai, bi ≤ n). That means that the fool number 2i - 1 lives in city ai and visits the fool number 2i, who lives in city bi. The given pairs describe simple paths, because between every pair of cities there is only one simple path.

Output

Print n - 1 integer. The integers should be separated by spaces. The i-th number should equal the number of fools who can go on the i-th road. The roads are numbered starting from one in the order, in which they occur in the input.

Examples

Input

5
1 2
1 3
2 4
2 5
2
1 4
3 5

Output

2 1 1 1 

Input

5
3 4
4 5
1 4
2 4
3
2 3
1 3
3 5

Output

3 1 1 1 

Note

In the first sample the fool number one goes on the first and third road and the fool number 3 goes on the second, first and fourth ones.

In the second sample, the fools number 1, 3 and 5 go on the first road, the fool number 5 will go on the second road, on the third road goes the fool number 3, and on the fourth one goes fool number 1.

这是一个裸的树上差分,树上差分的原理和数列差分的原理差不多。先写lca,对x到y的路径上的每一条边都加1,我们用一个差分数组,表示其与父亲的分数差,cha[x]++, cha[y]++, cha[lca]-2,然后dfs一次。在在回溯时,凭借儿子的经过数来求出自己的经过数。其实是把一条路径分成了 x 到 lca y到lca的两次数列差分,凭借树从后往前的回溯来算出结果。

#include<bits/stdc++.h>
using namespace std;
int cnt, n, m, nxt[200002], head[100002], g[200002], sum = 0;
int dep[100002], cha[100002], fa[100002][22], id[200002], ans[100002];
inline int read()
{
    int x = 0;
    char ch = getchar();
    while(ch >='0' && ch <= '9'){
        x=x*10+ch-'0';
        ch = getchar();
    }
    return x;
}
inline void addedge(int x, int y, int iid)
{
    cnt++;
    id[cnt] = iid;  
    g[cnt] = y;
    nxt[cnt] = head[x];
    head[x] = cnt;
}
inline void dfs(int x, int father, int dept)
{
    fa[x][0] = father;
    dep[x] = dept;
    for(int i = head[x]; i; i = nxt[i])
    {
        if(g[i] != father){
            dfs(g[i], x, dept+1);
        }
    }
}

void init()
{
    for(int i = 1; i <= 20; i++)
        for(int j = 1; j <= n; j++)
           fa[j][i] = fa[fa[j][i-1]][i-1]; 
}
void dfs2(int x, int fa){
//    cout<<x<<" "<<sum<<" "<<endl; 
    for(int i = head[x]; i; i = nxt[i])
    {
        if(g[i] != fa){
            dfs2(g[i], x);
            cha[x] += cha[g[i]];
            ans[id[i]] = cha[g[i]];
        }
    }
}
int main()
{
    n = read();
    for(int i = 1; i < n; i++)
    {
        int x = read(), y = read();
        addedge(x, y, i);
        addedge(y, x, i);
    }
    dfs(1, 0, 1);
    init();
    m = read();
    for(int i = 1; i <= m; i++)
    {
        int x, y, sx = read(), sy = read();
        if(dep[sx] < dep[sy]) swap(sx, sy);
        x = sx, y = sy;
        for(int i = 19; i >= 0; i--){
            if(dep[fa[x][i]] >= dep[y]) x = fa[x][i];
        }
        for(int i = 19; i >= 0; i--){
            if(fa[x][i] != fa[y][i])
            x = fa[x][i], y = fa[y][i];
        }
        int lca;
        if(x == y) lca = x;
        else lca = fa[x][0];
        cha[lca]-=2;
        cha[sx]++;
        cha[sy]++;
     //   cout<<lca<<" "<<sx<<" "<<sy<<" "<<cha[lca]<<" "<<cha[sx]<<" "<<cha[sy]<<endl; 
    }
    dfs2(1, 0);
    for(int i = 1; i < n; i++)
    printf("%d ", ans[i]);
    return 0;
}

3、

Ilya is very fond of graphs, especially trees. During his last trip to the forest Ilya found a very interesting tree rooted at vertex 1. There is an integer number written on each vertex of the tree; the number written on vertex i is equal to ai.

Ilya believes that the beauty of the vertex x is the greatest common divisor of all numbers written on the vertices on the path from the root to x, including this vertex itself. In addition, Ilya can change the number in one arbitrary vertex to 0 or leave all vertices unchanged. Now for each vertex Ilya wants to know the maximum possible beauty it can have.

For each vertex the answer must be considered independently.

The beauty of the root equals to number written on it.

Input
First line contains one integer number n — the number of vertices in tree (1 ≤ n ≤ 2·105).

Next line contains n integer numbers ai (1 ≤ i ≤ n, 1 ≤ ai ≤ 2·105).

Each of next n - 1 lines contains two integer numbers x and y (1 ≤ x, y ≤ n, x ≠ y), which means that there is an edge (x, y) in the tree.

Output
Output n numbers separated by spaces, where i-th number equals to maximum possible beauty of vertex i.

很简单的方法, 模拟一下就行了,用一个判重的set每一个点都继承父亲的所有可能性mod自己的值,再加入一路mod下来的值就行了。

#include<bits/stdc++.h>
using namespace std;
const int Maxn = 2e5+10;
int n, head[Maxn*2], g[Maxn*2], a[Maxn], cnt, nxt[Maxn*2];
set<int> s[Maxn];
void add(int x, int y){
    cnt++;
    g[cnt] = y;
    nxt[cnt] = head[x];
    head[x] = cnt;
} 
void dfs(int x, int fa, int now){
    for(auto p:s[fa]){
        s[x].insert(__gcd(p, a[x]));
    }
    s[x].insert(now);
    now = __gcd(now, a[x]);
    s[x].insert(now);
    for(int i = head[x]; i; i = nxt[i]){
        if(g[i] != fa){
            dfs(g[i], x, now);
        }
    }
}
int main()
{
    scanf("%d", &n);
    for(int i = 1; i <= n; i++)
    scanf("%d", &a[i]);
    for(int i = 1; i < n; i++){
        int x, y;
        scanf("%d %d", &x, &y);
        add(x, y);
        add(y, x);
    }
    dfs(1, 0, 0);
    for(int i = 1; i <= n; i++)
        printf("%d ", *s[i].rbegin());
    return 0;
}

4、

Paladin Manao caught the trail of the ancient Book of Evil in a swampy area. This area contains nsettlements numbered from 1 to n. Moving through the swamp is very difficult, so people tramped exactly n - 1 paths. Each of these paths connects some pair of settlements and is bidirectional. Moreover, it is possible to reach any settlement from any other one by traversing one or several paths.

The distance between two settlements is the minimum number of paths that have to be crossed to get from one settlement to the other one. Manao knows that the Book of Evil has got a damage range d. This means that if the Book of Evil is located in some settlement, its damage (for example, emergence of ghosts and werewolves) affects other settlements at distance d or less from the settlement where the Book resides.

Manao has heard of m settlements affected by the Book of Evil. Their numbers are p1, p2, ..., pm. Note that the Book may be affecting other settlements as well, but this has not been detected yet. Manao wants to determine which settlements may contain the Book. Help him with this difficult task.

Input

The first line contains three space-separated integers nm and d (1 ≤ m ≤ n ≤ 100000; 0 ≤ d ≤ n - 1). The second line contains m distinct space-separated integers p1, p2, ..., pm (1 ≤ pi ≤ n). Then n - 1 lines follow, each line describes a path made in the area. A path is described by a pair of space-separated integers aiand bi representing the ends of this path.

Output

Print a single number — the number of settlements that may contain the Book of Evil. It is possible that Manao received some controversial information and there is no settlement that may contain the Book. In such case, print 0.

要完成一个树的范围内的染色,我们先正着来一遍,算出子树的幽灵点到该点的最大距离,再搜一遍更新非子树的部分,分成由父亲与兄弟两部分。细节比较多:

1、注意数组的初始值,要初始化-1并进行特判,不然在取max的值时会出错

#include<bits/stdc++.h>
using namespace std;
const int Maxn = 2e5+10;
int n, head[Maxn*2], g[Maxn*2], a[Maxn], cnt, nxt[Maxn*2];
int ans[Maxn], Max[Maxn], dp[Maxn], f[Maxn], m, d;
bool in[Maxn];
void add(int x, int y){
    cnt++;
    g[cnt] = y;
    nxt[cnt] = head[x];
    head[x] = cnt;
} 
void dfs1(int x, int fa){
    f[x] = fa;
    if(in[x]) dp[x] = 0;
    for(int i = head[x]; i; i = nxt[i]){
        if(g[i] != fa){
            dfs1(g[i], x);
            if(dp[g[i]] + 1 > dp[x] && dp[g[i]] != -1){
                dp[x] = dp[g[i]] + 1;
                Max[x] = g[i]; 
            }
        }
    }
}
void dfs2(int x, int fa){
    if(in[x]) ans[x] = 0;
    if(fa != 0) {
    if(ans[fa] != -1) ans[x] = max(ans[x], ans[fa] + 1);
    if(Max[fa] == x){
    for(int i = head[fa]; i; i = nxt[i]){
        if(g[i] != fa && g[i] != x && g[i] != f[fa]){
             if(dp[g[i]] != -1) ans[x] = max(ans[x], dp[g[i]] + 2); 
        }
    }
    }else if(Max[fa] != -1) ans[x] = max(ans[x], dp[Max[fa]] + 2);
    }
    for(int i = head[x]; i; i = nxt[i]){
        if(g[i] != fa)
           dfs2(g[i], x);
    }
}
int main()
{
    scanf("%d %d %d", &n, &m, &d);
    for(int i = 1; i <= m; i++){
        int x;
        scanf("%d", &x);
        in[x] = 1;
    }
    for(int i = 1; i < n; i++){
        int x, y;
        scanf("%d %d", &x, &y);
        add(x, y);
        add(y, x);
    }
    memset(dp, -1, sizeof(dp));
    memset(Max, -1, sizeof(Max));
    memset(ans, -1, sizeof(ans));
    dfs1(1, 0);
    dfs2(1, 0);
    int res = 0;
    for(int i = 1; i <= n; i++){
        ans[i] = max(ans[i], dp[i]);
        if(ans[i] <= d) res++;
    }
    cout<<res;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/gjc2561571372/article/details/81169920