感觉和幻想乡那道题差别不是很大
每一层排序后用一个数据结构来维护
因为没有修改直接每个点维护子树信息
排序后每次询问二分前缀和就可以了
记录一下每个点自己的答案和对父亲的贡献
相减一下就可以了
具体可以参考代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define pb push_back
const int RLEN=1<<22|1;
inline char gc(){
static char ibuf[RLEN],*ib,*ob;
(ib==ob)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
return (ib==ob)?EOF:*ib++;
}
inline int read(){
char ch=gc();
int res=0,f=1;
while(!isdigit(ch)){if(ch=='-')f=1;ch=gc();}
while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
return res*f;
}
const int N=150005;
struct Mos{
int old,dis;ll sum;
Mos(int o=0,int d=0,ll s=0):old(o),dis(d),sum(s){}
friend inline bool operator <(const Mos &a,const Mos &b){
return a.old<b.old;
}
};
vector<Mos> f1[N],f2[N];
int adj[N],nxt[N<<1],to[N<<1],val[N<<1],lg[N<<2],siz[N],pos[N],son[N],maxn,dfn,rt,cnt,fa[N],vis[N];
int n,q,A,x[N];
ll st[N<<2][22],dis[N];
inline void addedge(int u,int v,int w){
nxt[++cnt]=adj[u],adj[u]=cnt,to[cnt]=v,val[cnt]=w;
}
void dfs(int u,int f){
st[++dfn][0]=dis[u],pos[u]=dfn;
for(re int e=adj[u];e;e=nxt[e]){
int v=to[e];
if(v==f)continue;
dis[v]=dis[u]+val[e];
dfs(v,u),st[++dfn][0]=dis[u];
}
}
inline void init(){
dfs(1,0),lg[0]=-1;
for(re int i=1;i<=n*4;i++)lg[i] = lg[i >> 1] + 1;
for(re int i=1;(1<<i)<=dfn;i++){
for(re int j=1;j+(1<<i)-1<=dfn;j++){
st[j][i]=min(st[j][i-1],st[j+(1<<(i-1))][i-1]);
}
}
}
inline ll dist(int u,int v){
int x=pos[u],y=pos[v];
if(x>y)swap(x,y);
int t=lg[y-x+1];
return dis[u]+dis[v]-2*min(st[x][t],st[y-(1<<t)+1][t]);
}
void getrt(int u,int f){
siz[u]=1,son[u]=0;
for(re int e=adj[u];e;e=nxt[e]){
int v=to[e];if(v==f||vis[v])continue;
getrt(v,u),siz[u]+=siz[v];
if(siz[v]>son[u])son[u]=siz[v];
}
son[u]=max(son[u],maxn-siz[u]);
if(son[u]<son[rt])rt=u;
}
void solve(int u){
vis[u]=1;
for(re int e=adj[u];e;e=nxt[e]){
int v=to[e];
if(vis[v])continue;
son[0]=maxn=siz[v],getrt(v,rt=0),fa[rt]=u,solve(rt);
}
}
inline ll query(int u,int k){
ll res=0;
for(re int i=u;i;i=fa[i]){
int p=lower_bound(f1[i].begin(),f1[i].end(),Mos(k,0,0))-f1[i].begin()-1;
res+=f1[i][p].sum+1ll*p*dist(u,i);
}
for(re int i=u;fa[i];i=fa[i]){
int p=lower_bound(f2[i].begin(),f2[i].end(),Mos(k,0,0))-f2[i].begin()-1;
res-=f2[i][p].sum+1ll*p*dist(u,fa[i]);
}
return res;
}
int main(){
// freopen("lx.cpp","r",stdin);
n=read(),q=read(),A=read();
for(int i=1;i<=n;i++)x[i]=read();
for(int i=1;i<n;i++){
int u=read(),v=read(),w=read();
addedge(u,v,w),addedge(v,u,w);
}
maxn=son[0]=n;
init(),getrt(1,rt=0);solve(rt);
for(re int i=1;i<=n;i++){
for(re int u=i;u;u=fa[u]){
f1[u].pb(Mos(x[i],dist(u,i),0)),f2[u].pb(Mos(x[i],dist(fa[u],i),0));
}
}
for(re int u=1;u<=n;u++){
f1[u].pb(Mos(-1,0,0)),f1[u].pb(Mos(RLEN,0,0));
f2[u].pb(Mos(-1,0,0)),f2[u].pb(Mos(RLEN,0,0));
sort(f1[u].begin(),f1[u].end());
sort(f2[u].begin(),f2[u].end());
for(re int j=1;j<f1[u].size();j++)f1[u][j].sum=f1[u][j].dis+f1[u][j-1].sum;
for(re int j=1;j<f2[u].size();j++)f2[u][j].sum=f2[u][j].dis+f2[u][j-1].sum;
}
ll last=0;
for(re int i=1;i<=q;i++){
int u=read(),x=read(),y=read();
x=(x+last)%A,y=(y+last)%A;
if(x>y)swap(x,y);
cout<<(last=(query(u,y+1)-query(u,x)))<<'
';
}
}