CodeForces 376F Tree and Queries(假·树上莫队)

You have a rooted tree consisting of n vertices. Each vertex of the tree has some color. We will assume that the tree vertices are numbered by integers from 1 to n. Then we represent the color of vertex v as cv. The tree root is a vertex with number 1.

In this problem you need to answer to m queries. Each query is described by two integers vj, kj. The answer to query vj, kj is the number of such colors of vertices x, that the subtree of vertex vj contains at least kj vertices of color x.

You can find the definition of a rooted tree by the following link: http://en.wikipedia.org/wiki/Tree_(graph_theory).

Input

The first line contains two integers n and m (2 ≤ n ≤ 105; 1 ≤ m ≤ 105). The next line contains a sequence of integers c1, c2, ..., cn(1 ≤ ci ≤ 105). The next n - 1 lines contain the edges of the tree. The i-th line contains the numbers ai, bi (1 ≤ ai, bi ≤ nai ≠ bi) — the vertices connected by an edge of the tree.

Next m lines contain the queries. The j-th line contains two integers vj, kj (1 ≤ vj ≤ n; 1 ≤ kj ≤ 105).

Output

Print m integers — the answers to the queries in the order the queries appear in the input.

Examples
input
Copy
8 5
1 2 2 3 3 2 3 3
1 2
1 5
2 3
2 4
5 6
5 7
5 8
1 2
1 3
1 4
2 3
5 3
output
Copy
2
2
1
0
1
input
Copy
4 1
1 2 3 4
1 2
2 3
3 4
1 1
output
Copy
4
Note

A subtree of vertex v in a rooted tree with root r is a set of vertices {u : dist(r, v) + dist(v, u) = dist(r, u)}. Where dist(x, y) is the length (in edges) of the shortest path between vertices x and y.

 

题意:给你一颗根为一有n个点的树,每个点有一个颜色值,给出m个询问,询问x子树中出现颜色数大于等于k的颜色数

题解:dfs序一遍,子树查询就变成了区间查询,然后就可以考虑莫队了,这个莫队也非常高妙,因为每次每个点只会加一或者减一,然后就可以动态维护后缀和了,这个听起来很高级,仔细看看代码还是很简单的。

代码如下:

#include<cmath>
#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

struct node
{
    int l,r,k,id;
}q[100010];

int sz,n,m,a[100010],ans[100010],dfsn[100010],size[100010],w[100010],c[100010],sum[100010],cnt[100010],tot,tot1;
vector<int> g[100010];

int block(int x)
{
    return (x+1)/sz;
}

int cmp(node a,node b)
{
    if(block(a.l)==block(b.l))
    {
        return a.r<b.r;
    }
    return a.l<b.l;
}

void add(int x)
{
    cnt[c[x]]++;
    sum[cnt[c[x]]]++;
}

void del(int x)
{
    sum[cnt[c[x]]]--;
    cnt[c[x]]--;
}

void dfs(int now,int f)
{
    dfsn[now]=++tot;
    c[tot]=w[now];
    size[now]=1;
    for(int i=0;i<g[now].size();i++)
    {
        if(g[now][i]==f)
        {
            continue;
        }
        dfs(g[now][i],now);
        size[now]+=size[g[now][i]];
    }
}

int main()
{
    scanf("%d%d",&n,&m);
    sz=sqrt(n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&w[i]);
    }
    for(int i=1;i<n;i++)
    {
        int from,to;
        scanf("%d%d",&from,&to);
        g[from].push_back(to);
        g[to].push_back(from);
    }
    dfs(1,0);
    for(int i=1;i<=m;i++)
    {
        int x,k;
        scanf("%d%d",&x,&k);
        q[++tot1].k=k;
        q[tot1].l=dfsn[x];
        q[tot1].r=dfsn[x]+size[x]-1;
        q[tot1].id=i;
    }
    sort(q+1,q+tot1+1,cmp);
    int nowl=1,nowr=0;
    for(int i=1;i<=m;i++)
    {
        while(nowl<q[i].l) del(nowl++);
        while(nowl>q[i].l) add(--nowl);
        while(nowr<q[i].r) add(++nowr);
        while(nowr>q[i].r) del(nowr--);
        ans[q[i].id]=sum[q[i].k];
    }
    for(int i=1;i<=m;i++)
    {
        printf("%d\n",ans[i]);
    }
}

 

posted @ 2018-04-27 21:02  Styx-ferryman  阅读(225)  评论(0编辑  收藏  举报