先考虑一个子问题:仅有一个询问且无修改
对每一种颜色的贡献分类讨论,结论:最远的点一定这些点集中(任意一组)最远点对中的两个点(选择较远的一个)
证明:设$dis(x,y)$为$x$到$y$的距离,$deep_{x}$表示以$k$为根时$x$的深度
假设这个点集中最远点为$(x,y)$,而最深的点为$z$,且$deep_{z}$严格大于$deep_{x}$和$deep_{y}$
一个显然的性质:$deep_{lca(x,y)}\le deep_{x},deep_{y}$
考虑$w=lca(x,y,z)$,若$z=w$与$deep_{z}>deep_{x},deep_{y}$矛盾,因此假设$z$在$w$的某个儿子$w_{z}$中
当若$x$和$y$都在$w_{z}$的子树中显然$lca(x,y,z)$可以为$w_{z}$,因此必然存在一个点在其子树外,不妨设为是$x$,则$lca(x,z)=w$,必然有$deep_{w}\le deep_{lca(x,y)}$
考虑此时$dis(x,z)$与$dis(x,y)$,通过lca的形式展开,由于$deep_{z}>deep_{y}$且$deep_{w}\le deep_{lca(x,y)}$,因此$dis(x,z)>dis(x,y)$,与$(x,y)$为最远点对矛盾
通过合并的方式(即不断插入一个点,三个点两两求$dis$)求出每一个点集的最远点对$(x,y)$,这一部分可以做到$o(n\log_{2}n)$
进一步的,不妨假设$deep_{x}\ge deep_{y}$(此时的$deep$为以1为根),通过倍增找到$z$满足$z$在$x$到$lca(x,y)$的路径上且$dis(x,z)<\lceil\frac{dis(x,y)}{2}\rceil$中$dis(x,z)$最大,那么$k$满足$dis(k,y)>dis(k,x)$当且仅当$k$在$z$子树中
特别的,当$x=y$时令$z=x$,这是为了方便处理,证明比较显然,这里就省略了
接下来,考虑对答案的贡献,分为两部分:
1.$z$的子树中,点$k$的答案加上$deep_{y}+deep_{k}-2depp_{lca(x,y)}$,首尾两个式子都为常数,线段树+dfs序即可,$deep_{k}$通过打“区间加点深度”的标记,再维护区间内所有点深度和即可处理
2.$z$的子树外,考虑$deep_{x}+deep_{k}-2deep_{lca(x,k)}$,前两个式子与上面处理方式相同,考虑第三个式子——
再建一棵线段树,将$fa_{z}$到根的路径打上“减2倍其到父亲的边权”,那么一个点所需要减的就是其到根路径上所有点的和,同时对$z$的子树内部没有影响,因此应对$z$的子树区间加$fa_{z}$的深度
这个考虑在询问时处理,假设询问$k$的子树,对于$k$到根路径上的所有点都会被减小$k$子树大小次,之后对于$k$子树内部的点会被减小子树大小次
分别维护这个值以及这个值乘对应子树大小的两颗线段树就可以处理了,另外链修改需要树链剖分,总复杂度为$o(n\log^{2}n)$
(注意,这样两颗线段树是独立的,也就是对两边的贡献用不同的方式计算)
对于修改,可以看作在某种颜色中插入/删除一个点,对于插入同样直径合并(之后重新修改),删除可以用线段树来做,同样利用直径合并的性质就可以做了(注意修改完直径后都要重新计算贡献)
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 200005 4 #define ll long long 5 #define L (k<<1) 6 #define R (L+1) 7 #define mid (l+r>>1) 8 #define pii pair<int,int> 9 #define fi first 10 #define se second 11 struct ji{ 12 int nex,to,len; 13 }edge[N]; 14 int E,n,m,t,x,p,a[N],head[N],d1[N],d2[N],sz[N],son[N],dfn[N],inv_dfn[N],top[N],fa[N][21]; 15 int V,pos[N],rt[N],ls[N*40],rs[N*40]; 16 vector<int>v[N]; 17 pii fd[N*40]; 18 ll val[4][N<<2],tag[4][N<<2],f[4][N<<2]; 19 void add(int x,int y,int z){ 20 edge[E].nex=head[x]; 21 edge[E].to=y; 22 edge[E].len=z; 23 head[x]=E++; 24 } 25 void dfs1(int k,int s1,int s2){ 26 d1[k]=s1; 27 d2[k]=s2; 28 sz[k]=1; 29 for(int i=1;i<=20;i++)fa[k][i]=fa[fa[k][i-1]][i-1]; 30 for(int i=head[k];i!=-1;i=edge[i].nex) 31 if (edge[i].to!=fa[k][0]){ 32 dfs1(edge[i].to,s1+1,s2+edge[i].len); 33 sz[k]+=sz[edge[i].to]; 34 if ((!son[k])||(sz[son[k]]<sz[edge[i].to]))son[k]=edge[i].to; 35 } 36 } 37 void dfs2(int k,int t){ 38 dfn[k]=++x; 39 inv_dfn[x]=k; 40 top[k]=t; 41 if (son[k])dfs2(son[k],t); 42 for(int i=head[k];i!=-1;i=edge[i].nex){ 43 int u=edge[i].to; 44 if ((u!=fa[k][0])&&(u!=son[k]))dfs2(u,u); 45 } 46 } 47 int lca(int x,int y){ 48 if (d1[x]<d1[y])swap(x,y); 49 for(int i=20;i>=0;i--) 50 if (d1[fa[x][i]]>=d1[y])x=fa[x][i]; 51 if (x==y)return x; 52 for(int i=20;i>=0;i--) 53 if (fa[x][i]!=fa[y][i]){ 54 x=fa[x][i]; 55 y=fa[y][i]; 56 } 57 return fa[x][0]; 58 } 59 int dis(int x,int y){ 60 if ((!x)||(!y))return 0; 61 return d2[x]+d2[y]-2*d2[lca(x,y)]; 62 } 63 pii merge(pii x,pii y){ 64 int d=0,a[5]; 65 pair<int,int>ans=make_pair(0,0); 66 a[0]=0; 67 if (x.fi)a[++a[0]]=x.fi; 68 if (x.se)a[++a[0]]=x.se; 69 if (y.fi)a[++a[0]]=y.fi; 70 if (y.se)a[++a[0]]=y.se; 71 if (a[0]==1)return make_pair(a[1],0); 72 for(int i=1;i<=a[0];i++) 73 for(int j=i+1;j<=a[0];j++){ 74 int dd=dis(a[i],a[j]); 75 if (dd>d){ 76 d=dd; 77 ans=make_pair(a[i],a[j]); 78 } 79 } 80 return ans; 81 } 82 void update(int &k,int l,int r,int x,int y){ 83 if (!k)k=++V; 84 if (l==r){ 85 fd[k]=make_pair(y,0); 86 return; 87 } 88 if (x<=mid)update(ls[k],l,mid,x,y); 89 else update(rs[k],mid+1,r,x,y); 90 fd[k]=merge(fd[ls[k]],fd[rs[k]]); 91 } 92 void up(int k){ 93 for(int i=0;i<4;i++)f[i][k]=f[i][L]+f[i][R]; 94 } 95 void upd(int p,int k,int x){ 96 tag[p][k]+=x; 97 f[p][k]+=x*val[p][k]; 98 } 99 void down(int k){ 100 for(int i=0;i<4;i++) 101 if (tag[i][k]){ 102 upd(i,L,tag[i][k]); 103 upd(i,R,tag[i][k]); 104 tag[i][k]=0; 105 } 106 } 107 void build(int k,int l,int r){ 108 if (l==r){ 109 x=inv_dfn[l]; 110 val[0][k]=1; 111 val[1][k]=d2[x]; 112 if (x==1)val[2][k]=0; 113 else val[2][k]=d2[x]-d2[fa[x][0]]; 114 val[3][k]=val[2][k]*sz[x]; 115 return; 116 } 117 build(L,l,mid); 118 build(R,mid+1,r); 119 for(int i=0;i<4;i++)val[i][k]=val[i][L]+val[i][R]; 120 } 121 void update(int p,int k,int l,int r,int x,int y,int z){ 122 if ((l>y)||(x>r))return; 123 if ((x<=l)&&(r<=y)){ 124 upd(p,k,z); 125 return; 126 } 127 down(k); 128 update(p,L,l,mid,x,y,z); 129 update(p,R,mid+1,r,x,y,z); 130 up(k); 131 } 132 ll query(int p,int k,int l,int r,int x,int y){ 133 if ((l>y)||(x>r))return 0; 134 if ((x<=l)&&(r<=y))return f[p][k]; 135 down(k); 136 return query(p,L,l,mid,x,y)+query(p,R,mid+1,r,x,y); 137 } 138 void calc(int k,int p){ 139 int x=fd[rt[k]].fi,y=fd[rt[k]].se; 140 if (!x)return; 141 int z; 142 if (!y)z=y=x; 143 else{ 144 if (d2[x]<d2[y])swap(x,y); 145 z=x; 146 int d=(dis(x,y)+1)/2; 147 for(int i=20;i>=0;i--) 148 if (d2[x]-d2[fa[z][i]]<d)z=fa[z][i]; 149 } 150 update(0,1,1,n,dfn[z],dfn[z]+sz[z]-1,p*(d2[y]-2*d2[lca(x,y)])); 151 update(0,1,1,n,1,dfn[z]-1,p*d2[x]); 152 update(0,1,1,n,dfn[z]+sz[z],n,p*d2[x]); 153 update(1,1,1,n,1,n,p); 154 update(0,1,1,n,dfn[z],dfn[z]+sz[z]-1,2*p*d2[fa[z][0]]); 155 z=fa[z][0]; 156 while (z>1){ 157 update(2,1,1,n,dfn[top[z]],dfn[z],-2*p); 158 update(3,1,1,n,dfn[top[z]],dfn[z],-2*p); 159 z=fa[top[z]][0]; 160 } 161 } 162 ll query(int k){ 163 ll ans=0; 164 for(int i=0;i<4;i++) 165 if (i!=2)ans+=query(i,1,1,n,dfn[k],dfn[k]+sz[k]-1); 166 int x=sz[k]; 167 k=fa[k][0]; 168 while (k>1){ 169 ans+=x*query(2,1,1,n,dfn[top[k]],dfn[k]); 170 k=fa[top[k]][0]; 171 } 172 return ans; 173 } 174 int main(){ 175 scanf("%d%d%d",&n,&t,&m); 176 for(int i=1;i<=n;i++){ 177 scanf("%d",&a[i]); 178 v[a[i]].push_back(i); 179 pos[i]=v[a[i]].size(); 180 } 181 memset(head,-1,sizeof(head)); 182 fa[1][0]=1; 183 for(int i=2;i<=n;i++)scanf("%d",&fa[i][0]); 184 for(int i=2;i<=n;i++){ 185 scanf("%d",&x); 186 add(fa[i][0],i,x); 187 } 188 dfs1(1,0,0); 189 x=0; 190 dfs2(1,1); 191 build(1,1,n); 192 for(int i=1;i<=n;i++)update(rt[a[i]],1,n+m,pos[i],i); 193 for(int i=1;i<=t;i++)calc(i,1); 194 for(int i=1;i<=m;i++){ 195 scanf("%d%d",&p,&x); 196 if (p==2)printf("%lld\n",query(x)); 197 else{ 198 calc(a[x],-1); 199 update(rt[a[x]],1,n+m,pos[x],0); 200 calc(a[x],1); 201 scanf("%d",&a[x]); 202 calc(a[x],-1); 203 v[a[x]].push_back(x); 204 pos[x]=v[a[x]].size(); 205 update(rt[a[x]],1,n+m,pos[x],x); 206 calc(a[x],1); 207 } 208 } 209 }View Code