BZOJ 3626 [LNOI2014]LCA:树剖 + 差分 + 离线将深度转化成点权之和

Posted Leohh

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ 3626 [LNOI2014]LCA:树剖 + 差分 + 离线将深度转化成点权之和相关的知识,希望对你有一定的参考价值。

题意:

  给出一个n个节点的有根树(编号为0到n-1,根节点为0,n <= 50000)。

  一个点的深度定义为这个节点到根的距离+1。

  设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先。

  有q次询问,每次询问给出l,r,z,求∑ dep[LCA(i,z)] (l<=i<=r)。

  (即,求在[l,r]区间内的每个节点i与z的最近公共祖先的深度之和)

 

题解:

  假设有一棵所有点都为0的树。

  如果将x到root路径上的点都+1,则dep[LCA(x,y)] = y到root路径上的点权之和,且这个操作具有叠加性。(树剖)

  所以对于询问query(l to r) = query(r) - query(l-1)。(差分)

  显然,只需要求出在询问中有的l和r的query。

  所以依次枚举节点i = 0 to n-1,将i到root的路径+1,如果i是某一些询问的l或r,则记录相应的query(z)。(离线)

  总复杂度O((n+q)*logn*logn)

 

AC Code:

  1 #include <iostream>
  2 #include <stdio.h>
  3 #include <string.h>
  4 #include <vector>
  5 #define MAX_N 200005
  6 #define MAX_M 50005
  7 #define MOD 201314
  8 
  9 using namespace std;
 10 
 11 struct Query
 12 {
 13     int ver;
 14     int id;
 15     int dr;
 16     Query(int _ver,int _id,int _dr)
 17     {
 18         ver=_ver;
 19         id=_id;
 20         dr=_dr;
 21     }
 22     Query(){};
 23 };
 24 
 25 int n,m;
 26 int tot=0;
 27 int cnt=0;
 28 int l[MAX_M];
 29 int r[MAX_M];
 30 int z[MAX_M];
 31 int dat[MAX_N];
 32 int lazy[MAX_N];
 33 int lson[MAX_N];
 34 int rson[MAX_N];
 35 int par[MAX_N];
 36 int dep[MAX_N];
 37 int siz[MAX_N];
 38 int tp[MAX_N];
 39 int son[MAX_N];
 40 int dfsx[MAX_N];
 41 int ans[MAX_M][2];
 42 vector<int> edge[MAX_N];
 43 vector<Query> q[MAX_M];
 44 
 45 inline int mod(int x)
 46 {
 47     return (x%MOD+MOD)%MOD;
 48 }
 49 
 50 int build(int l,int r)
 51 {
 52     int rt=++tot;
 53     dat[rt]=lazy[rt]=0;
 54     lson[rt]=rson[rt]=0;
 55     if(l<r)
 56     {
 57         int mid=(l+r)>>1;
 58         lson[rt]=build(l,mid);
 59         rson[rt]=build(mid+1,r);
 60     }
 61     return rt;
 62 }
 63 
 64 void push_down(int k,int len)
 65 {
 66     if(lazy[k])
 67     {
 68         if(lson[k])
 69         {
 70             dat[lson[k]]=mod(dat[lson[k]]+lazy[k]*(len-(len>>1)));
 71             lazy[lson[k]]=mod(lazy[lson[k]]+lazy[k]);
 72         }
 73         if(rson[k])
 74         {
 75             dat[rson[k]]=mod(dat[rson[k]]+lazy[k]*(len>>1));
 76             lazy[rson[k]]=mod(lazy[rson[k]]+lazy[k]);
 77         }
 78         lazy[k]=0;
 79     }
 80 }
 81 
 82 void push_up(int k)
 83 {
 84     dat[k]=0;
 85     if(lson[k]) dat[k]=mod(dat[k]+dat[lson[k]]);
 86     if(rson[k]) dat[k]=mod(dat[k]+dat[rson[k]]);
 87 }
 88 
 89 void update(int a,int b,int k,int l,int r,int x)
 90 {
 91     if(a<=l && r<=b)
 92     {
 93         dat[k]=mod(dat[k]+(r-l+1)*x);
 94         lazy[k]=mod(lazy[k]+x);
 95         return;
 96     }
 97     if(r<a || b<l) return;
 98     push_down(k,r-l+1);
 99     int mid=(l+r)>>1;
100     update(a,b,lson[k],l,mid,x);
101     update(a,b,rson[k],mid+1,r,x);
102     push_up(k);
103 }
104 
105 int query(int a,int b,int k,int l,int r)
106 {
107     if(a<=l && r<=b) return dat[k];
108     if(r<a || b<l) return 0;
109     push_down(k,r-l+1);
110     int mid=(l+r)>>1;
111     int v1=query(a,b,lson[k],l,mid);
112     int v2=query(a,b,rson[k],mid+1,r);
113     return mod(v1+v2);
114 }
115 
116 void dfs1(int now,int d)
117 {
118     dep[now]=d;
119     siz[now]=1;
120     for(int i=0;i<edge[now].size();i++)
121     {
122         int temp=edge[now][i];
123         if(temp!=par[now])
124         {
125             dfs1(temp,d+1);
126             siz[now]+=siz[temp];
127         }
128     }
129 }
130 
131 void dfs2(int now,int anc)
132 {
133     tp[now]=anc;
134     son[now]=-1;
135     dfsx[now]=++cnt;
136     for(int i=0;i<edge[now].size();i++)
137     {
138         int temp=edge[now][i];
139         if((son[now]==-1 || siz[temp]>siz[son[now]]) && temp!=par[now])
140         {
141             son[now]=temp;
142         }
143     }
144     if(son[now]!=-1) dfs2(son[now],anc);
145     for(int i=0;i<edge[now].size();i++)
146     {
147         int temp=edge[now][i];
148         if(temp!=par[now] && temp!=son[now]) dfs2(temp,temp);
149     }
150 }
151 
152 void update_chain(int a,int x)
153 {
154     while(tp[a]!=0)
155     {
156         update(dfsx[tp[a]],dfsx[a],1,1,n,x);
157         a=par[tp[a]];
158     }
159     update(1,dfsx[a],1,1,n,x);
160 }
161 
162 int query_chain(int a)
163 {
164     int sum=0;
165     while(tp[a]!=0)
166     {
167         sum=mod(sum+query(dfsx[tp[a]],dfsx[a],1,1,n));
168         a=par[tp[a]];
169     }
170     sum=mod(sum+query(1,dfsx[a],1,1,n));
171     return sum;
172 }
173 
174 void read()
175 {
176     scanf("%d%d",&n,&m);
177     for(int i=1;i<n;i++)
178     {
179         scanf("%d",&par[i]);
180         edge[i].push_back(par[i]);
181         edge[par[i]].push_back(i);
182     }
183 }
184 
185 void solve()
186 {
187     build(1,n);
188     dfs1(0,0);
189     dfs2(0,0);
190     for(int i=0;i<m;i++)
191     {
192         scanf("%d%d%d",&l[i],&r[i],&z[i]);
193         if(l[i]>0) q[l[i]-1].push_back(Query(z[i],i,0));
194         q[r[i]].push_back(Query(z[i],i,1));
195     }
196     memset(ans,0,sizeof(ans));
197     for(int i=0;i<n;i++)
198     {
199         update_chain(i,1);
200         for(int j=0;j<q[i].size();j++)
201         {
202             Query temp=q[i][j];
203             ans[temp.id][temp.dr]=query_chain(temp.ver);
204         }
205     }
206 }
207 
208 void print()
209 {
210     for(int i=0;i<m;i++)
211     {
212         printf("%d\n",mod(ans[i][1]-ans[i][0]));
213     }
214 }
215 
216 int main()
217 {
218     read();
219     solve();
220     print();
221 }

 

以上是关于BZOJ 3626 [LNOI2014]LCA:树剖 + 差分 + 离线将深度转化成点权之和的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ3626[LNOI2014]LCA 离线+树链剖分+线段树

bzoj3626 [LNOI2014]LCA

BZOJ 3626: [LNOI2014]LCA 树链剖分 线段树 离线

BZOJ 3626 [LNOI2014]LCA在线+主席树+树剖

bzoj3626[LNOI2014]LCA 树链剖分+线段树

BZOJ 3626 [LNOI2014]LCA