BZOJ - 4771 七彩树 (可持久化线段树合并)

题目链接

对每个结点建立两棵线段树,一棵记录该结点的子树下每种颜色对应的最小深度,另一棵记录子树下的每个深度有多少结点(每种颜色的结点只保留最浅的深度即可),自底而上令父节点继承子结点的线段树,如果合并两棵颜色线段树时发现某种颜色重复,则在深度线段树上把较深的深度对应的位置-1。

注意由于强制在线,深度线段树的合并以及更新都需要可持久化。

(ps:不能用map代替颜色线段树,会TLE~~)

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 typedef double db;
 5 const int N=1e5+10;
 6 int n,m,hd[N],ne,rt1[N],rt2[N],tot1,tot2,a[N],dep[N];
 7 struct E {int v,nxt;} e[N];
 8 struct D1 {int ls,rs,x;} tr1[N*40];
 9 struct D2 {int ls,rs,x;} tr2[N*80];
10 void addedge(int u,int v) {e[ne]= {v,hd[u]},hd[u]=ne++;}
11 #define mid ((l+r)>>1)
12 int newnode1() {tr1[++tot1]= {0,0,0}; return tot1;}
13 int newnode2() {tr2[++tot2]= {0,0,0}; return tot2;}
14 void upd1(int& u,int p,int x,int l=1,int r=n) {
15     if(!u)u=newnode1();
16     if(l==r) {tr1[u].x=x; return;}
17     p<=mid?upd1(tr1[u].ls,p,x,l,mid):upd1(tr1[u].rs,p,x,mid+1,r);
18 }
19 void upd2(int& w,int u,int p,int x,int l=1,int r=n) {
20     w=newnode2();
21     tr2[w].x=tr2[u].x+x;
22     if(l==r)return;
23     if(p<=mid)upd2(tr2[w].ls,tr2[u].ls,p,x,l,mid),tr2[w].rs=tr2[u].rs;
24     else upd2(tr2[w].rs,tr2[u].rs,p,x,mid+1,r),tr2[w].ls=tr2[u].ls;
25 }
26 void mg1(int uu,int& u,int v,int l=1,int r=n) {
27     if(!u) {u=v; return;}
28     if(!v)return;
29     if(l==r) {
30         if(!tr1[u].x)tr1[u].x=tr1[v].x;
31         else if(!tr1[v].x);
32         else {
33             int mx=max(tr1[u].x,tr1[v].x),mi=min(tr1[u].x,tr1[v].x);
34             upd2(rt2[uu],rt2[uu],mx,-1),tr1[u].x=mi;
35         }
36         return;
37     }
38     mg1(uu,tr1[u].ls,tr1[v].ls,l,mid);
39     mg1(uu,tr1[u].rs,tr1[v].rs,mid+1,r);
40 }
41 void mg2(int& w,int u,int v,int l=1,int r=n) {
42     if(!u) {w=v; return;}
43     if(!v) {w=u; return;}
44     w=newnode2();
45     tr2[w].x=tr2[u].x+tr2[v].x;
46     if(l==r)return;
47     mg2(tr2[w].ls,tr2[u].ls,tr2[v].ls,l,mid);
48     mg2(tr2[w].rs,tr2[u].rs,tr2[v].rs,mid+1,r);
49 }
50 void dfs(int u,int d) {
51     rt1[u]=rt2[u]=0,dep[u]=d;
52     upd1(rt1[u],a[u],dep[u]),upd2(rt2[u],rt2[u],dep[u],1);
53     for(int i=hd[u]; ~i; i=e[i].nxt) {
54         int v=e[i].v;
55         dfs(v,d+1);
56         mg1(u,rt1[u],rt1[v]);
57         mg2(rt2[u],rt2[u],rt2[v]);
58     }
59 }
60 int qry(int u,int L,int R,int l=1,int r=n) {
61     if(l>=L&&r<=R)return tr2[u].x;
62     if(l>R||r<L)return 0;
63     return qry(tr2[u].ls,L,R,l,mid)+qry(tr2[u].rs,L,R,mid+1,r);
64 }
65 int main() {
66     int T;
67     for(scanf("%d",&T); T--;) {
68         memset(hd,-1,sizeof hd),ne=tot1=tot2=0;
69         scanf("%d%d",&n,&m);
70         for(int i=1; i<=n; ++i)scanf("%d",&a[i]);
71         for(int i=2; i<=n; ++i) {
72             int f;
73             scanf("%d",&f);
74             addedge(f,i);
75         }
76         dfs(1,1);
77         for(int ans=0; m--;) {
78             int u,d;
79             scanf("%d%d",&u,&d),u^=ans,d^=ans;
80             printf("%d\n",ans=qry(rt2[u],1,min(dep[u]+d,n)));
81         }
82     }
83     return 0;
84 }

 

转载于:https://www.cnblogs.com/asdfsag/p/10677271.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值