根据树上距离的计算方法,可以先把答案化成$sum dep_i+n*dep_u-sum 2*dep[LCA(i,u)]$的形式,然后维护$sum 2*dep[LCA(i,u)]$
把妖怪们按年龄排序,轻重剖分后插入每个点到根的路径,记录经过次数,询问也是往根跳然后每次统计边权*次数。
可持久化线段树+差分
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int N=300005,M=1e7+70,inf=1e9; 6 int root[N],son[M][2],num[M]; 7 int p[N],noww[N],goal[N],val[N]; 8 int siz[N],far[N],imp[N],top[N],dfn[N]; 9 long long dis[N],sum1[N],sum2[N],sum[M],ans; 10 int n,m,nm,rt,t1,t2,t3,rot,cnt,tot; 11 struct a 12 { 13 int age,idx; 14 }mon[N]; 15 bool operator < (a x,a y) 16 { 17 return x.age==y.age?x.idx<y.idx:x.age<y.age; 18 } 19 void Link(int f,int t,int v) 20 { 21 noww[++cnt]=p[f],p[f]=cnt; 22 goal[cnt]=t,val[cnt]=v; 23 noww[++cnt]=p[t],p[t]=cnt; 24 goal[cnt]=f,val[cnt]=v; 25 } 26 void DFS(int nde,int fth) 27 { 28 int tmp=0; 29 siz[nde]=1,far[nde]=fth; 30 for(int i=p[nde],g;i;i=noww[i]) 31 if((g=goal[i])!=fth) 32 { 33 dis[g]=dis[nde]+val[i]; 34 DFS(g,nde),siz[nde]+=siz[g]; 35 if(siz[g]>tmp) tmp=siz[g],imp[nde]=g; 36 } 37 } 38 void Mark(int nde,int tpp) 39 { 40 top[nde]=tpp,dfn[nde]=++tot; 41 sum1[tot]=dis[nde]-dis[far[nde]]; 42 if(imp[nde]) 43 { 44 Mark(imp[nde],tpp); 45 for(int i=p[nde],g;i;i=noww[i]) 46 if((g=goal[i])!=far[nde]&&g!=imp[nde]) Mark(g,g); 47 } 48 } 49 50 int Insert(int pre,int l,int r,int ll,int rr) 51 { 52 int nde=++tot; 53 son[nde][0]=son[pre][0]; 54 son[nde][1]=son[pre][1]; 55 num[nde]=num[pre],sum[nde]=sum[pre]; 56 if(l==ll&&r==rr) num[nde]++; 57 else 58 { 59 int mid=(l+r)>>1; 60 sum[nde]+=sum1[rr]-sum1[ll-1]; 61 if(mid>=rr) son[nde][0]=Insert(son[pre][0],l,mid,ll,rr); 62 else if(mid<ll) son[nde][1]=Insert(son[pre][1],mid+1,r,ll,rr); 63 else son[nde][0]=Insert(son[pre][0],l,mid,ll,mid), 64 son[nde][1]=Insert(son[pre][1],mid+1,r,mid+1,rr); 65 } 66 return nde; 67 } 68 long long Query(int nde,int l,int r,int ll,int rr) 69 { 70 long long ret=(sum1[rr]-sum1[ll-1])*num[nde]; 71 if(l==ll&&r==rr) 72 return ret+sum[nde]; 73 else 74 { 75 int mid=(l+r)>>1; 76 if(mid>=rr) return ret+Query(son[nde][0],l,mid,ll,rr); 77 else if(mid<ll) return ret+Query(son[nde][1],mid+1,r,ll,rr); 78 else return ret+Query(son[nde][0],l,mid,ll,mid)+Query(son[nde][1],mid+1,r,mid+1,rr); 79 } 80 } 81 82 int Change(int nde) 83 { 84 while(top[nde]!=rt) 85 rot=Insert(rot,1,n,dfn[top[nde]],dfn[nde]),nde=far[top[nde]]; 86 return rot=Insert(rot,1,n,1,dfn[nde]); 87 } 88 long long Ask(int trt,int nde) 89 { 90 long long ret=0; 91 while(top[nde]!=rt) 92 ret+=Query(trt,1,n,dfn[top[nde]],dfn[nde]),nde=far[top[nde]]; 93 return ret+Query(trt,1,n,1,dfn[nde]); 94 } 95 96 int main() 97 { 98 scanf("%d%d%d",&n,&m,&nm),rt=1; 99 for(int i=1;i<=n;i++) 100 scanf("%d",&t1),mon[i]=(a){t1,i}; 101 sort(mon+1,mon+1+n); 102 for(int i=1;i<n;i++) 103 scanf("%d%d%d",&t1,&t2,&t3),Link(t1,t2,t3); 104 DFS(1,0),Mark(1,1); 105 for(int i=1;i<=n;i++) 106 sum1[i]+=sum1[i-1],sum2[i]=sum2[i-1]+dis[mon[i].idx]; 107 for(int i=1;i<=n;i++) 108 root[i]=Change(mon[i].idx); 109 for(int i=1;i<=m;i++) 110 { 111 scanf("%d%d%d",&t1,&t2,&t3); 112 t2=(ans+t2)%nm,t3=(ans+t3)%nm; 113 if(t2>t3) swap(t2,t3); 114 int ll=lower_bound(mon+1,mon+1+n,(a){t2,0})-mon; 115 int rr=upper_bound(mon+1,mon+1+n,(a){t3,inf})-mon-1; 116 // printf("%d==%d==%d==%d==%d==",ll,rr,dis[t1]*(rr-ll+1),sum2[rr]-sum2[ll-1],2*(Ask(root[rr],t1)-Ask(root[ll-1],t1))); 117 printf("%lld ",ans=dis[t1]*(rr-ll+1)+sum2[rr]-sum2[ll-1]-2*(Ask(root[rr],t1)-Ask(root[ll-1],t1))); 118 } 119 return 0; 120 }