传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4012
思路:首先我们考虑一个简化的问题:
给定一棵树,每次询问所有点到一个点的距离和。
画个图就能知道:距离和=所有点到根的距离和+点数*u到根的距离-每个点与u的lca到根的距离*2
于是问题就成了求lca的dis和
那么我们先对每个点,把它到根的路径覆盖一次,然后询问点u时就是从u向上跳,每次加覆盖次数*边权
用树链剖分即可
但是现在每个点多了一个点权,有了限制条件:只计算点权要在[l,r]内的点到u的距离。
对于区间最大最小等问题我们用的是线段树,对于区间内且权值在[a,b]间的点的询问,我们就用可持久化线段树。
这题也一样,先按点权(年龄)从小到大排序,离散化,按点权顺序把每个点到根的路径覆盖一次。
像对序列的问题一样,询问年龄在[l,r]中的lca的dis和,就是[1,r]的距离和-[1,l]的距离和。
然后就没有然后了
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
const int maxn=150010,maxm=300010,maxt=10000010;
typedef long long ll;
using namespace std;
int n,m,mod,age[maxn],pre[maxm],now[maxn],son[maxm],val[maxm],tot,tim;
int last[maxn],root[maxn],rt; ll ans,sumdis[maxn],sumE[maxn],dis[maxn];
int top[maxn],dep[maxn],hson[maxn],dfn[maxn],fa[maxn],siz[maxn];
struct Monster{int age,id;}mon[maxn];
void add(int a,int b,int c){pre[++tot]=now[a],now[a]=tot,son[tot]=b,val[tot]=c;}
bool operator<(Monster a,Monster b){return a.age!=b.age?a.age<b.age:a.id<b.id;}
struct TSegment_tree{
ll sum[maxt];int ls[maxt],rs[maxt],tot,time[maxt];
int modify(int p,int l,int r,int a,int b){
int x=++tot,mid=(l+r)>>1;
ls[x]=ls[p],rs[x]=rs[p],sum[x]=sum[p],time[x]=time[p];
if (l==a&&r==b){time[x]++;return x;}
sum[x]+=(sumE[b]-sumE[a-1]);
if (b<=mid) ls[x]=modify(ls[x],l,mid,a,b);
else if (a>mid) rs[x]=modify(rs[x],mid+1,r,a,b);
else ls[x]=modify(ls[x],l,mid,a,mid),rs[x]=modify(rs[x],mid+1,r,mid+1,b);
return x;
}
ll query(int p,int l,int r,int a,int b){
ll res=1ll*(sumE[b]-sumE[a-1])*time[p];
if (l==a&&r==b){return res+sum[p];}
int mid=(l+r)>>1;
if (b<=mid) return res+query(ls[p],l,mid,a,b);
else if (a>mid) return res+query(rs[p],mid+1,r,a,b);
else return res+query(ls[p],l,mid,a,mid)+query(rs[p],mid+1,r,mid+1,b);
}
}T;
void dfs(int x){
siz[x]=1;
for (int y=now[x];y;y=pre[y])if (son[y]!=fa[x]){
fa[son[y]]=x,dis[son[y]]=dis[x]+val[y],last[son[y]]=val[y];
dfs(son[y]),siz[x]+=siz[son[y]];
if (siz[son[y]]>siz[hson[x]]) hson[x]=son[y];
}
}
void btree(int x,int tp){
sumE[dfn[x]=++tim]=last[x],top[x]=tp;
if (hson[x]) btree(hson[x],tp);
for (int y=now[x];y;y=pre[y])
if (hson[x]!=son[y]&&son[y]!=fa[x])
btree(son[y],son[y]);
}
int modify(int x){
while (top[x]!=1){rt=T.modify(rt,1,n,dfn[top[x]],dfn[x]),x=fa[top[x]];}
return rt=T.modify(rt,1,n,1,dfn[x]);
}
ll query(int rt,int x){
ll res=0;
while (top[x]!=1){res+=T.query(rt,1,n,dfn[top[x]],dfn[x]),x=fa[top[x]];}
return res+T.query(rt,1,n,1,dfn[x]);
}
int main(){
scanf("%d%d%d",&n,&m,&mod);
for (int i=1;i<=n;i++) scanf("%d",&mon[i].age),mon[i].id=i;
sort(mon+1,mon+1+n);
for (int i=1,a,b,c;i<n;i++) scanf("%d%d%d",&a,&b,&c),add(a,b,c),add(b,a,c);
dfs(1),btree(1,1);
for (int i=1;i<=n;i++) sumE[i]+=sumE[i-1],sumdis[i]=sumdis[i-1]+dis[mon[i].id];
for (int i=1;i<=n;i++) root[i]=modify(mon[i].id);
for (int i=1,a,b,u;i<=m;i++){
scanf("%d%d%d",&u,&a,&b);
a=(1ll*a+ans)%mod,b=(1ll*b+ans)%mod;
if (a>b) swap(a,b);
a=lower_bound(mon+1,mon+1+n,(Monster){a,0})-mon,b=upper_bound(mon+1,mon+1+n,(Monster){b,(int)1e9})-mon-1;
ans=1ll*(b-a+1)*dis[u]+sumdis[b]-sumdis[a-1]-2ll*((query(root[b],u)-query(root[a-1],u)));
printf("%lld\n",ans);
}
return 0;
}