[HDU5709]Claris Loves Painting

有一个$n$个点的树,每个点有一个颜色,每次询问$x$点子树内距离小于等于$d$的点的颜色个数,强制在线

超级妙的一道题

首先我们可以想想如果不强制在线我们可以怎么做

$Dsu$ $on$ $tree$!

首先把所有询问离线下来,然后用$vector$存下来每个点的询问

按照深度建一个线段树表示深度小于等于$i$的点颜色个数有多少,开一个数组$d_i$表示颜色$i$出现的最低深度是多少

很显然如果$d_i$都无法对答案产生贡献,那么子树内就不存在能对答案产生贡献的颜色$i$

然后我们暴力遍历轻儿子的时候,如果当先前点为颜色$i$且当前点的深度小于$d_i$,就可以更新$d_i$的值

然后从线段树中删除之前的$d_i$的贡献,假如新的$d_i$的贡献,最后查询线段树回答询问即可

如果在线做我们也是要建一个类似的线段树保证查询的复杂度,问题是我们该如何求出子树中每种颜色最低的深度

假如我们事先已经知道一个点$x$的所有子树内颜色的最低深度,那么我们就可以利用线段树合并把他们合起来

然后对于回答询问的线段树的修改与之前是一样的,所以我们开两颗权值线段树就可以做出来这道题了

代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #define M 100010
 5 using namespace std;
 6 int n,m,T,cnt,ans;
 7 int fa[M],deep[M],c[M],rt1[M],rt2[M];
 8 int val[M<<7],ch[M<<7][2];
 9 int insert(int rt,int l,int r,int pos,int v)
10 {
11     int node=++cnt;val[node]=val[rt]+v;
12     if(l==r) return node;
13     int mid=(l+r)/2;
14     ch[node][0]=ch[rt][0],ch[node][1]=ch[rt][1];
15     if(pos<=mid) ch[node][0]=insert(ch[rt][0],l,mid,pos,v);
16     else ch[node][1]=insert(ch[rt][1],mid+1,r,pos,v);
17     return node;
18 }
19 int merge1(int x,int y,int l,int r)
20 {
21     if(!x||!y) return x+y;
22     int node=++cnt;val[node]=val[x]+val[y];
23     if(l==r) return node;
24     int mid=(l+r)/2;
25     ch[node][0]=merge1(ch[x][0],ch[y][0],l,mid);
26     ch[node][1]=merge1(ch[x][1],ch[y][1],mid+1,r);
27     return node;
28 }
29 int merge2(int x,int y,int l,int r,int id)
30 {
31     if(!x||!y) return x+y;
32     int node=++cnt;
33     if(l==r)
34     {
35         if(val[x]>val[y]) val[node]=val[y],rt1[id]=insert(rt1[id],1,n,val[x],-1);
36         else val[node]=val[x],rt1[id]=insert(rt1[id],1,n,val[y],-1);
37         return node;
38     }
39     int mid=(l+r)/2;
40     ch[node][0]=merge2(ch[x][0],ch[y][0],l,mid,id);
41     ch[node][1]=merge2(ch[x][1],ch[y][1],mid+1,r,id);
42     return node;
43 }
44 int query(int node,int l,int r,int l1,int r1)
45 {
46     if(!node) return 0;
47     if(l1==l&&r1==r) return val[node];
48     int mid=(l+r)/2;
49     if(r1<=mid) return query(ch[node][0],l,mid,l1,r1);
50     else if(l1>mid) return query(ch[node][1],mid+1,r,l1,r1);
51     else return query(ch[node][0],l,mid,l1,mid)+query(ch[node][1],mid+1,r,mid+1,r1);
52 }
53 void work()
54 {
55     cnt=ans=0;
56     scanf("%d%d",&n,&m);
57     for(int i=1;i<=n;i++) scanf("%d",&c[i]);
58     for(int i=2;i<=n;i++) scanf("%d",&fa[i]);
59     for(int i=1;i<=n;i++) deep[i]=deep[fa[i]]+1;
60     for(int i=1;i<=n;i++)
61     {
62         rt1[i]=insert(0,1,n,deep[i],1);
63         rt2[i]=insert(0,1,n,c[i],deep[i]);
64     }
65     for(int i=n;i>=2;i--)
66     {
67         rt1[fa[i]]=merge1(rt1[fa[i]],rt1[i],1,n);
68         rt2[fa[i]]=merge2(rt2[fa[i]],rt2[i],1,n,fa[i]);
69     }
70     for(int i=1;i<=m;i++)
71     {
72         int x,d;scanf("%d%d",&x,&d);
73         x^=ans,d^=ans;
74         ans=query(rt1[x],1,n,deep[x],min(deep[x]+d,n));
75         printf("%d
",ans);
76     }
77 }
78 int main()
79 {
80     scanf("%d",&T);
81     while(T--) work();
82     return 0;
83 }
原文地址:https://www.cnblogs.com/Slrslr/p/10014768.html