可以点分树做,也可以树链剖分+主席树
询问
∑
v
∈
[
l
,
r
]
d
i
s
(
u
,
v
)
\sum_{v∈[l,r]}{dis(u,v)}
∑v∈[l,r]dis(u,v)就是求
(
r
−
l
+
1
)
∗
d
e
p
[
u
]
+
∑
v
∈
[
l
,
r
]
d
e
p
[
v
]
−
2
∗
∑
v
∈
[
l
,
r
]
d
e
p
[
l
c
a
(
u
,
v
)
]
(r-l+1)*dep[u]+\sum_{v∈[l,r]}dep[v]-2*\sum_{v∈[l,r]}{dep[lca(u,v)]}
(r−l+1)∗dep[u]+∑v∈[l,r]dep[v]−2∗∑v∈[l,r]dep[lca(u,v)],前面两项
O
(
1
)
O(1)
O(1),最后一项实际上是把每个点到根的路径上的所有点打上一个标记,然后询问u到根节点的路径上的标记数,如果没有年龄的限制,就直接线段树做了
有限制的话,按照年龄排序建主席树,然后区间查询就很简单了
Code:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline int read(){
int res=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-f;ch=getchar();}
while(isdigit(ch)) {res=(res<<1)+(res<<3)+(ch^48);ch=getchar();}
return res*f;
}
const int N=1.5e5+5;
ll presum[N],sum[N];
namespace President_tree{
struct seg{int ls,rs,cnt;ll sum;}tr[N*150];int tot;
#define lc(k) tr[k].ls
#define rc(k) tr[k].rs
void build(int &k,int l,int r){
k=++tot;
if(l==r) return;
int mid=l+r>>1;
build(lc(k),l,mid);build(rc(k),mid+1,r);
}
void ins(int &rt1,int l,int r,int ql,int qr){
tr[++tot]=tr[rt1];
if(l==ql && r==qr){++tr[rt1=tot].cnt;return;}
tr[rt1=tot].sum+=sum[qr]-sum[ql-1];
int mid=l+r>>1;
if(qr<=mid) ins(lc(rt1),l,mid,ql,qr);
else if(ql>mid) ins(rc(rt1),mid+1,r,ql,qr);
else ins(lc(rt1),l,mid,ql,mid),ins(rc(rt1),mid+1,r,mid+1,qr);
}
ll query(int rt,int l,int r,int ql,int qr){
ll res=1ll*(sum[qr]-sum[ql-1])*tr[rt].cnt;
if(l==ql && r==qr) return res+tr[rt].sum;
int mid=l+r>>1;
if(qr<=mid) return res+query(lc(rt),l,mid,ql,qr);
else if(ql>mid) return res+query(rc(rt),mid+1,r,ql,qr);
else return res+query(lc(rt),l,mid,ql,mid)+query(rc(rt),mid+1,r,mid+1,qr);
}
}
using namespace President_tree;
int n,rt[N];
namespace tree{
int vis[N<<1],nxt[N<<1],head[N],c[N<<1],tot=0;
inline void add(int x,int y,int z){vis[++tot]=y;nxt[tot]=head[x];head[x]=tot;c[tot]=z;}
int siz[N],fa[N],hson[N],dep[N],pt[N];
void dfs1(int v){
pt[v]=siz[v]=1;
for(int i=head[v];i;i=nxt[i]){
int y=vis[i];
if(pt[y]) continue;
fa[y]=v;dep[y]=dep[v]+c[i];
dfs1(y);
siz[v]+=siz[y];
if(siz[y]>siz[hson[v]]) hson[v]=y;
}
}
int dfn[N],id[N],sign=0,top[N];
void dfs2(int v){
dfn[v]=++sign,sum[sign]=dep[v]-dep[fa[v]];
if(hson[v]) top[hson[v]]=top[v],dfs2(hson[v]);
for(int i=head[v];i;i=nxt[i])
if(!top[vis[i]]) top[vis[i]]=vis[i],dfs2(vis[i]);
}
inline ll ask(int rt1,int v){
ll res=0;
while(top[v]!=1) res+=query(rt[rt1],1,n,dfn[top[v]],dfn[v]),v=fa[top[v]];
return res+query(rt[rt1],1,n,1,dfn[v]);
}
}
using namespace tree;
struct point{
int age,id;
point(){}
point(int _age,int _id):age(_age),id(_id){}
}p[N];
inline bool operator < (point a,point b){return a.age==b.age?a.id<b.id:a.age<b.age;}
ll ans=0;
int main(){
n=read();int q=read(),mod=read();
for(int x,i=1;i<=n;i++) x=read(),p[i]=point(x,i);
sort(p+1,p+n+1);
for(int x,y,z,i=1;i<n;i++){
x=read();y=read();z=read();
add(x,y,z);add(y,x,z);
}
dfs1(1);top[1]=1;dfs2(1);
for(int i=1;i<=n;i++) sum[i]+=sum[i-1],presum[i]=presum[i-1]+dep[p[i].id];
build(rt[0],1,n);
for(int i=1;i<=n;i++){
int v=p[i].id;rt[i]=rt[i-1];
while(top[v]!=1) ins(rt[i],1,n,dfn[top[v]],dfn[v]),v=fa[top[v]];
ins(rt[i],1,n,1,dfn[v]);
}
while(q--){
int u=read(),l=read(),r=read();
l=(1ll*l+ans)%mod,r=(1ll*r+ans)%mod;
if(l>r) swap(l,r);
l=lower_bound(p+1,p+n+1,point(l,0))-p;
r=upper_bound(p+1,p+n+1,point(r,n))-p-1;
ans=1ll*(r-l+1)*dep[u]+presum[r]-presum[l-1]-2*(ask(r,u)-ask(l-1,u));
cout<<ans<<"\n";
}
return 0;
}