BZOJ 3626 LCA(离线+树链剖分+差分)
显然,暴力求解的复杂度是无法承受的。
考虑这样的一种暴力,我们把 z 到根上的点全部打标记,对于 l 到 r
之间的点,向上搜索到第一个有标记的点求出它的深度统计答案。观察到,深度其实就是上面有几个已标记了的点(包括自身)。所以,我们不妨把 z
到根的路径上的点全部 +1,对于 l 到 r
之间的点询问他们到根路径上的点权和。仔细观察上面的暴力不难发现,实际上这个操作具有叠加性,且可逆。也就是说我们可以对于 l 到 r 之间的点
i,将 i 到根的路径上的点全部 +1, 转而询问 z 到根的路径上的点(包括自身)的权值和就是这个询问的答案。把询问差分下,也就是用 [1,
r] − [1, l − 1] 来计算答案,那么现在我们就有一个明显的解法。从 0 到 n − 1 依次插入点 i,即将 i
到根的路径上的点全部+1。离线询问答案即可。我们现在需要一个数据结构来维护路径加和路径求和,显然树链剖分或LCT
均可以完成这个任务。树链剖分的复杂度为 O((n + q)· log n · log n),LCT的复杂度为 O((n + q)· log
n),均可以完成任务。至此,题目已经被我们完美解决。
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<cmath> 5 #include<algorithm> 6 #include<vector> 7 using namespace std; 8 const long long N=51100; 9 const long long mod=201314; 10 long long cnt,head[N]; 11 long long size[N],fa[N],dep[N],son[N]; 12 long long top[N],id[N],tot; 13 long long n,m,lm[N],rm[N]; 14 struct que{ 15 long long l,r,z; 16 }q[N]; 17 struct tree{ 18 long long l,r,sum,lazy; 19 }tr[N*8]; 20 vector<long long> l[N],r[N]; 21 struct edge{ 22 long long to,nxt; 23 }e[N*2]; 24 void add(long long u,long long v){ 25 cnt++; 26 e[cnt].nxt=head[u]; 27 e[cnt].to=v; 28 head[u]=cnt; 29 } 30 void dfs1(long long u,long long f,long long deep){ 31 size[u]=1; 32 fa[u]=f; 33 dep[u]=deep; 34 long long maxson=-1; 35 for(long long i=head[u];i;i=e[i].nxt){ 36 long long v=e[i].to; 37 if(v==f)continue; 38 dfs1(v,u,deep+1); 39 size[u]+=size[v]; 40 if(size[v]>maxson){ 41 maxson=size[v]; 42 son[u]=v; 43 } 44 } 45 } 46 void dfs2(long long u,long long tp){ 47 top[u]=tp; 48 id[u]=++tot; 49 if(!son[u])return; 50 dfs2(son[u],tp); 51 for(long long i=head[u];i;i=e[i].nxt){ 52 long long v=e[i].to; 53 if(v==fa[u]||v==son[u])continue; 54 dfs2(v,v); 55 } 56 } 57 void build(long long l,long long r,long long now){ 58 tr[now].l=l;tr[now].r=r; 59 if(l==r)return; 60 long long mid=(l+r)>>1; 61 build(l,mid,now*2); 62 build(mid+1,r,now*2+1); 63 } 64 void update(long long now){ 65 tr[now].sum=tr[now*2].sum+tr[now*2+1].sum; 66 tr[now].sum%=mod; 67 } 68 void pushdown(long long now){ 69 if(tr[now].lazy==0)return; 70 tr[now*2].sum+=((tr[now*2].r-tr[now*2].l+1)*tr[now].lazy)%mod; 71 tr[now*2].sum%=mod; 72 tr[now*2+1].sum+=((tr[now*2+1].r-tr[now*2+1].l+1)*tr[now].lazy)%mod; 73 tr[now*2+1].sum%=mod; 74 tr[now*2].lazy+=tr[now].lazy; 75 tr[now*2].lazy%=mod; 76 tr[now*2+1].lazy+=tr[now].lazy; 77 tr[now*2+1].lazy%=mod; 78 tr[now].lazy=0; 79 } 80 void change(long long l,long long r,long long now){ 81 pushdown(now); 82 if(tr[now].l==l&&tr[now].r==r){ 83 tr[now].sum+=(tr[now].r-tr[now].l+1)%mod; 84 tr[now].sum%=mod; 85 tr[now].lazy+=1; 86 return; 87 } 88 long long mid=(tr[now].l+tr[now].r)>>1; 89 if(l>mid)change(l,r,now*2+1); 90 else if(r<=mid)change(l,r,now*2); 91 else{ 92 change(l,mid,now*2); 93 change(mid+1,r,now*2+1); 94 } 95 update(now); 96 } 97 long long getsum(long long l,long long r,long long now){ 98 pushdown(now); 99 if(tr[now].l==l&&tr[now].r==r){ 100 return tr[now].sum; 101 } 102 long long mid=(tr[now].l+tr[now].r)>>1; 103 if(l>mid)return getsum(l,r,now*2+1); 104 else if(r<=mid)return getsum(l,r,now*2); 105 else { 106 return (getsum(l,mid,now*2)+getsum(mid+1,r,now*2+1))%mod; 107 } 108 } 109 void changel(long long x,long long y){ 110 while(top[x]!=top[y]){ 111 if(dep[top[x]]<dep[top[y]])swap(x,y); 112 change(id[top[x]],id[x],1); 113 x=fa[top[x]]; 114 } 115 if(dep[x]>dep[y])swap(x,y); 116 change(id[x],id[y],1); 117 } 118 long long getsuml(long long x,long long y){ 119 long long ans=0; 120 while(top[x]!=top[y]){ 121 if(dep[top[x]]<dep[top[y]])swap(x,y); 122 ans+=getsum(id[top[x]],id[x],1); 123 ans%=mod; 124 x=fa[top[x]]; 125 } 126 if(dep[x]>dep[y])swap(x,y); 127 ans+=getsum(id[x],id[y],1); 128 ans%=mod; 129 return ans; 130 } 131 int main(){ 132 scanf("%lld%lld",&n,&m); 133 for(long long i=2;i<=n;i++){ 134 long long u; 135 scanf("%lld",&u); 136 add(u+1,i);add(i,u+1); 137 } 138 dfs1(1,0,1); 139 dfs2(1,1); 140 build(1,n,1); 141 for(long long i=1;i<=m;i++){ 142 scanf("%lld%lld%lld",&q[i].l,&q[i].r,&q[i].z); 143 q[i].l++;q[i].r++;q[i].z++; 144 l[q[i].l-1].push_back(i); 145 r[q[i].r].push_back(i); 146 } 147 for(long long i=1;i<=n;i++){ 148 changel(i,1); 149 for(long long j=0;j<l[i].size();j++){ 150 lm[l[i][j]]=getsuml(q[l[i][j]].z,1); 151 } 152 for(long long j=0;j<r[i].size();j++){ 153 rm[r[i][j]]=getsuml(q[r[i][j]].z,1); 154 } 155 } 156 for(long long i=1;i<=m;i++){ 157 printf("%lld\n",(rm[i]-lm[i]+mod)%mod); 158 } 159 return 0; 160 }