1. 程式人生 > >BZOJ 3626 [LNOI2014]LCA:樹剖 + 差分 + 離線【將深度轉化成點權之和】

BZOJ 3626 [LNOI2014]LCA:樹剖 + 差分 + 離線【將深度轉化成點權之和】

scanf tor chain stdio.h dfs lca uil sin ems

題意:

  給出一個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:樹剖 + 差分 + 離線【將深度轉化成點權之和】