题解:动态点分治
建立点分树
每个点维护点分树子树内节点到这个节点和父亲节点距离的前缀和
二分查找锁定合法区间
对每个祖先分治中心查询路径和然后减去不合法子树内的路径和
注意:求大量LCA时用树剖
不开O2时少用STL
相乘炸int
lower_bound和upper_bound返回值边界
注意常数
#include<iostream> #include<cstdio> #include<cstring> #include<vector> #include<algorithm> using namespace std; const int maxn=200009; const int oo=1000000000; typedef long long Lint; int n,T,u; int a[maxn]; int cntedge; int head[maxn]; int to[maxn<<1],nex[maxn<<1],dist[maxn<<1]; void Addedge(int x,int y,int z){ nex[++cntedge]=head[x]; to[cntedge]=y; dist[cntedge]=z; head[x]=cntedge; } int nowsiz,root; int vis[maxn]; int siz[maxn],g[maxn]; void Getsiz(int x,int fa){ siz[x]=1; for(int i=head[x];i;i=nex[i]){ if(vis[to[i]])continue; if(to[i]==fa)continue; Getsiz(to[i],x); siz[x]+=siz[to[i]]; } } void Getroot(int x,int fa){ siz[x]=1; g[x]=0; for(int i=head[x];i;i=nex[i]){ if(vis[to[i]])continue; if(to[i]==fa)continue; Getroot(to[i],x); siz[x]+=siz[to[i]]; g[x]=max(g[x],siz[to[i]]); } g[x]=max(g[x],nowsiz-siz[x]); if(g[x]<g[root])root=x; } int divfa[maxn]; void Sol(int x){ vis[x]=1; Getsiz(x,0); for(int i=head[x];i;i=nex[i]){ if(vis[to[i]])continue; root=0;nowsiz=siz[to[i]]; Getroot(to[i],x); divfa[root]=x; Sol(root); } } int father[maxn],dep[maxn],d[maxn],top[maxn],hson[maxn]; void Dfs(int x,int fa){ father[x]=fa; dep[x]=dep[fa]+1; siz[x]=1; for(int i=head[x];i;i=nex[i]){ if(to[i]==fa)continue; d[to[i]]=d[x]+dist[i]; Dfs(to[i],x); siz[x]+=siz[to[i]]; if(siz[to[i]]>siz[hson[x]])hson[x]=to[i]; } } void Dfs2(int x,int toppoint){ top[x]=toppoint; if(!hson[x])return; Dfs2(hson[x],toppoint); for(int i=head[x];i;i=nex[i]){ if(to[i]==father[x])continue; if(to[i]==hson[x])continue; Dfs2(to[i],to[i]); } } int Getlca(int u,int v){ int tu=top[u]; int tv=top[v]; while(tu!=tv){ if(dep[tu]<dep[tv]){ swap(u,v); swap(tu,tv); } u=father[tu]; tu=top[u]; } if(dep[u]<dep[v])return u; else return v; } int Getdist(int x,int y){ if((x==0)||(y==0))return 0; int lca=Getlca(x,y); return d[x]+d[y]-d[lca]-d[lca]; } vector<int>G[maxn]; vector<Lint>S[maxn]; vector<Lint>S2[maxn]; int cmp(const int &rhs1,const int &rhs2){ return a[rhs1]<a[rhs2]; } int main(){ scanf("%d%d%d",&n,&T,&u); for(int i=1;i<=n;++i)scanf("%d",&a[i]); for(int i=1;i<n;++i){ int x,y,z; scanf("%d%d%d",&x,&y,&z); Addedge(x,y,z); Addedge(y,x,z); } Dfs(1,0); Dfs2(1,1); g[0]=oo;root=0;nowsiz=n; Getroot(1,0); Sol(root); for(int i=1;i<=n;++i){ int x=i; while(x){ G[x].push_back(i); x=divfa[x]; } } // for(int i=1;i<=n;++i){ // for(int j=1;j<=n;++j){ // cout<<Getdist(i,j)<<‘ ‘; // } // cout<<endl; // } for(int i=1;i<=n;++i){ sort(G[i].begin(),G[i].end(),cmp); Lint now=0,now2=0; for(int j=0;j<G[i].size();++j){ now=now+Getdist(i,G[i][j]); now2=now2+Getdist(divfa[i],G[i][j]); S[i].push_back(now); S2[i].push_back(now2); G[i][j]=a[G[i][j]]; } // printf("=->%d %d %d\n",i,now,now2); } // for(int i=1;i<=n;++i)cout<<d[i]<<‘ ‘; // cout<<endl; Lint ans=0; while(T--){ int x,y,Lold,Rold; scanf("%d%d%d",&x,&Lold,&Rold); y=x; int t1=(Lold+ans)%u; int t2=(Rold+ans)%u; Lold=min(t1,t2); Rold=max(t1,t2); // cout<<Lold<<‘ ‘<<Rold<<endl; ans=0; int p=0; // cout<<ans<<endl; // for(int i=0;i<G[x].size();++i)cout<<G[x][i]<<‘ ‘; // cout<<endl; p=upper_bound(G[x].begin(),G[x].end(),Rold)-G[x].begin()-1; if(p>-1)ans+=S[x][p]; // cout<<p<<endl; p=lower_bound(G[x].begin(),G[x].end(),Lold)-G[x].begin(); if(p)ans-=S[x][p-1]; // cout<<p<<endl; // cout<<ans<<endl; while(divfa[x]){ Lint fdist=Getdist(divfa[x],y); int fa=divfa[x]; p=upper_bound(G[fa].begin(),G[fa].end(),Rold)-G[fa].begin()-1; if(p>-1)ans+=S[fa][p]+fdist*(p+1); // cout<<p<<‘ ‘; p=lower_bound(G[fa].begin(),G[fa].end(),Lold)-G[fa].begin(); if(p)ans-=S[fa][p-1]+fdist*p; // cout<<p<<endl; // cout<<ans<<endl; p=upper_bound(G[x].begin(),G[x].end(),Rold)-G[x].begin()-1; if(p>-1)ans-=S2[x][p]+fdist*(p+1); p=lower_bound(G[x].begin(),G[x].end(),Lold)-G[x].begin(); if(p)ans+=S2[x][p-1]+fdist*p; // cout<<ans<<endl; x=divfa[x]; } printf("%lld\n",ans); } return 0; }