链剖,居然还可以这样求LCA,学习了orz
这题很显然看出我还掌握离线处理QAQ
直接引用清华爷gconeice的题解吧
显然,暴力求解的复杂度是无法承受的。
考虑这样的一种暴力,我们把 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),均可以完成任务。至此,题目已经被我们完美解决。
吐槽一下。。pushdown居然连续写错2个,差一个就要半天QAQ
1 #include<bits/stdc++.h> 2 #define inc(i,l,r) for(int i=l;i<=r;i++) 3 #define dec(i,l,r) for(int i=l;i>=r;i--) 4 #define link(x) for(edge *j=h[x];j;j=j->next) 5 #define mem(a) memset(a,0,sizeof(a)) 6 #define inf 201314 7 #define ll long long 8 #define succ(x) (1<<x) 9 #define NM 50000+5 10 using namespace std; 11 int read(){ 12 int x=0,f=1;char ch=getchar(); 13 while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} 14 while(isdigit(ch))x=x*10+ch-'0',ch=getchar(); 15 return x*f; 16 } 17 struct info{ 18 ll z,s,size; 19 }T[8*NM],q[NM],null; 20 info operator+(const info&x,const info&y){ 21 info f; 22 f.s=x.s+y.s; 23 f.size=x.size+y.size; 24 f.z=0; 25 return f; 26 } 27 struct tmp{ 28 int t,x,z; 29 }a[2*NM]; 30 bool cmp(tmp x,tmp y){ 31 return x.x<y.x; 32 } 33 struct edge{ 34 int t,v; 35 edge *next; 36 }e[NM],*h[NM],*p=e; 37 void add(int x,int y){ 38 p->t=y;p->next=h[x];h[x]=p;p++; 39 } 40 int d[NM],f[NM],size[NM],son[NM],id[NM],_id[NM],top[NM],TOP,tot; 41 int num,n,m,_x,_y,l,r,t; 42 void dfs1(int x){ 43 link(x) 44 if(!f[j->t]){ 45 f[j->t]=x; 46 d[j->t]=d[x]+1; 47 dfs1(j->t); 48 size[x]+=size[j->t]; 49 if(size[j->t]>size[son[x]])son[x]=j->t; 50 } 51 size[x]++; 52 } 53 void dfs2(int x){ 54 top[x]=TOP;id[x]=++tot;_id[tot]=x; 55 if(son[x])dfs2(son[x]); 56 link(x) 57 if(!top[j->t])dfs2(TOP=j->t); 58 } 59 void pushdown(int i){ 60 if(T[i].z){ 61 T[i<<1].s+=T[i].z*T[i<<1].size; 62 T[i<<1|1].s+=T[i].z*T[i<<1|1].size; 63 T[i<<1].z+=T[i].z; 64 T[i<<1|1].z+=T[i].z; 65 T[i].z=0; 66 } 67 } 68 void build(int i,int x,int y){ 69 int t=x+y>>1; 70 if(x==y){ 71 T[i].size=1; 72 return; 73 } 74 build(i<<1,x,t);build(i<<1|1,t+1,y); 75 T[i]=T[i<<1]+T[i<<1|1]; 76 } 77 void ch(int i,int x,int y){ 78 int t=x+y>>1; 79 if(l<=x&&y<=r){ 80 T[i].z+=1;T[i].s+=T[i].size; 81 return; 82 } 83 if(y<l||r<x)return; 84 pushdown(i); 85 ch(i<<1,x,t);ch(i<<1|1,t+1,y); 86 T[i]=T[i<<1]+T[i<<1|1]; 87 } 88 void update(int x){ 89 while(top[x]!=1){ 90 l=id[top[x]];r=id[x]; 91 ch(1,1,n); 92 x=f[top[x]]; 93 } 94 l=id[1];r=id[x]; 95 ch(1,1,n); 96 } 97 info query(int i,int x,int y){ 98 int t=x+y>>1; 99 pushdown(i); 100 if(l<=x&&y<=r)return T[i]; 101 if(y<l||r<x)return null; 102 return query(i<<1,x,t)+query(i<<1|1,t+1,y); 103 } 104 int _query(int x){ 105 int s=0; 106 while(top[x]!=1){ 107 l=id[top[x]];r=id[x]; 108 s+=query(1,1,n).s; 109 x=f[top[x]]; 110 } 111 l=id[1];r=id[x]; 112 s+=query(1,1,n).s; 113 return s; 114 } 115 int main(){ 116 n=read();m=read(); 117 inc(i,2,n){ 118 _x=read()+1; 119 add(_x,i); 120 } 121 f[1]=1;null.s=0; 122 dfs1(1); 123 dfs2(TOP=1); 124 build(1,1,n); 125 inc(i,1,m){ 126 _x=read();_y=read()+1; 127 q[i].z=read()+1; 128 a[++num].x=_x;a[num].t=i;a[num].z=1; 129 a[++num].x=_y;a[num].t=i;a[num].z=0; 130 } 131 sort(a+1,a+num+1,cmp); 132 t=0; 133 inc(i,1,num){ 134 while(a[i].x>t){ 135 t++; 136 update(t); 137 // printf("%d\n",T[1].s); 138 } 139 _x=a[i].t; 140 if(a[i].z==1)q[_x].s-=_query(q[_x].z); 141 else q[_x].s+=_query(q[_x].z); 142 } 143 inc(i,1,m)printf("%d\n",q[i].s%inf); 144 return 0; 145 }