这题是看了解题报告做的。
第二种方法一直 TLE 。 是我写挫了 。
第一种是树状数组。
给每个节点一个起始位置和结束位置。这些位置值与节点标号没有关系。这样1-n 都会作为起始位置。给他们新的权值。
从1-n依次枚举,这里枚举的不是节点编号,而是位置。枚举到i时,树状数组的query(k) 求得的是k位置到i位置的答案。
查询时,按每个查询的点的结束位置从小到大排序。这样枚举到i位置,就把以i位置结束的都求出来。
int val[N], w[N], a[N], b[N], C[N], ans[N];
int n, k, cnt, e;
map<int, int>m;
vector<int>v[N];
vector<int>pl[N];
struct point
{
int s, t, id;
bool operator<(const point &x) const
{
return t<x.t;
}
}p[N];
void dfs(int s, int pre)
{
int i, ss;
a[s] = b[s] = ++cnt;
w[cnt] = val[s];
for(i=0; i<v[s].size(); i++)
{
ss = v[s][i];
if(ss==pre) continue;
dfs(ss, s);
b[s] = b[ss];
}
}
void in(int &a)
{
a = 0;
char ch;
while(ch=getchar(), ch<'0'||ch>'9');
a = ch-'0';
while(ch=getchar(), ch>='0'&&ch<='9') a = a*10+ch-'0';
}
inline int lowbit(int x)
{
return x&(-x);
}
void updata(int s, int vv)
{
for(; s<=n; s+=lowbit(s)) C[s] += vv;
}
int query(int s)
{
int ans = 0;
for(; s>0; s-=lowbit(s)) ans += C[s];
return ans;
}
int main()
{
int t, tt=0, q, x, y, i, j;
in(t);
while(t--)
{
memset(C, 0, sizeof(C));
for(i=1; i<=n; i++) v[i].clear();
m.clear();
cnt = e = 0;
in(n); in(k);
for(i=1; i<=n; i++)
{
in(x);
if (!m.count(x))
{
val[i] = m[x] = ++e;
pl[e].clear();
pl[e].push_back(0);
}
else val[i]=m[x];
}
for(i=1; i<n; i++)
{
in(x); in(y);
v[x].push_back(y);
v[y].push_back(x);
}
dfs(1, 0);
in(q);
printf("Case #%d:\n", ++tt);
for(i=1; i<=q; i++)
{
in(x);
p[i].s = a[x];
p[i].t = b[x];
p[i].id = i;
}
sort(p+1, p+q+1);
int h = 1;
for(i=1; i<=n; i++)
{
int vv = w[i];
int g = pl[vv].size();
pl[vv].push_back(i);
if(g>=k)
{
if(g>k) //减去一些值
{
updata(pl[vv][g-k-1]+1, -1);
updata(pl[vv][g-k]+1, 1);
}
updata(pl[vv][g-k]+1, 1); //加上一些值
updata(pl[vv][g-k+1]+1, -1);
}
while(p[h].t==i)
{
ans[ p[h].id ] = query(p[h].s);
h++;
}
}
for(i=1; i<=q; i++)
{
printf("%d\n", ans[i]);
}
if(t) puts("");
}
return 0;
}