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 离线+树链剖分+线段树
BZOJ 3626: [LNOI2014]LCA 树链剖分 线段树 离线
BZOJ 3626 [LNOI2014]LCA在线+主席树+树剖