题目大意
给出一棵有n个节点的树,每条边有个边长,每个节点有个权值a[i],有q个询问形如”u l r”询问点u到所有权值在l到r之间的点的路径长度和
一眼解法
一个点与多个点之间的距离和,显然我们可以用点分治来做,对于每个分治中心,我们将其所有该层的点都记录下来,那么每层共有n个,最多
nlog2n
个,同时,在我们计算答案时要计算每个分治中心对其父亲的影响。
询问时我们就直接在重心树上跳,沿途记录答案就好了。
贴代码:
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<iostream>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
typedef long long LL;
typedef double db;
const int N = 150010;
int n,Q,A;
int v[N];
int fa[N],q[N],m,s[N],vis[N],tim,mv[N];
bool bz[N];
int f[N];
struct point{
int x,v;
LL s;
}a[N*20];
int r[N],k,l[N];
int ce[N],rt[N*2],u,rmq[N*2][20],fir[N];
LL dis[N];
int h[N],tot;
struct edge{
int x,len,next;
}e[N*2];
int get(){
char ch;
int s=0;
while(ch=getchar(),ch<'0'||ch>'9');
s=ch-'0';
while(ch=getchar(),ch>='0'&&ch<='9')s=s*10+ch-'0';
return s;
}
void inse(int x,int y,int z){
e[++tot].x=y;
e[tot].len=z;
e[tot].next=h[x];
h[x]=tot;
}
void dfs(int x){
rt[fir[x]=++u]=x;
for(int p=h[x];p;p=e[p].next)
if (!fir[e[p].x]){
ce[e[p].x]=ce[x]+1;
dis[e[p].x]=dis[x]+e[p].len;
dfs(e[p].x);
rt[++u]=x;
}
}
void getrmq(){
fo(i,1,u)rmq[i][0]=rt[i];
fo(j,1,log(u)/log(2))
fo(i,1,u-(1<<j)+1)
if (ce[rmq[i][j-1]]<ce[rmq[i+(1<<(j-1))][j-1]])rmq[i][j]=rmq[i][j-1];
else rmq[i][j]=rmq[i+(1<<(j-1))][j-1];
}
LL getdis(int x,int y){
if (!x||!y)return 0;
LL ans=dis[x]+dis[y];
x=fir[x],y=fir[y];
if (x>y)swap(x,y);
int t=log(y-x+1)/log(2);
if (ce[rmq[x][t]]<ce[rmq[y-(1<<t)+1][t]])return ans-2*dis[rmq[x][t]];
return ans-2*dis[rmq[y-(1<<t)+1][t]];
}
bool cmp(point x,point y){
return x.v<y.v;
}
void bfs(int x){
vis[q[m=1]=x]=++tim;
s[x]=1;
mv[x]=0;
int head=0;
while(head<m){
x=q[++head];
for(int p=h[x];p;p=e[p].next)
if (!bz[e[p].x]&&vis[e[p].x]<tim){
vis[q[++m]=e[p].x]=tim;
fa[e[p].x]=x;
s[e[p].x]=1;
mv[e[p].x]=0;
}
}
}
int solve(int x,int last){
bfs(x);
int w=0;
fd(i,m,1){
x=q[i];
s[fa[x]]+=s[x];
mv[fa[x]]=max(mv[fa[x]],s[x]);
mv[x]=max(mv[x],m-s[x]);
if (mv[x]*2<=m)w=x;
}
bz[w]=1;
l[w]=k;
r[w]=k+m;
fo(i,1,m){
a[++k].x=q[i];
a[k].v=v[q[i]];
}
sort(a+l[w]+1,a+r[w]+1,cmp);
fo(i,l[w]+1,l[w]+m){
x=a[i].x;
if (last)a[i].s=getdis(last,x);
a[i].s=getdis(w,x)-a[i].s;
if (i>l[w]+1)a[i].s=a[i].s+a[i-1].s;
}
for(int p=h[w];p;p=e[p].next)
if (!bz[e[p].x])f[solve(e[p].x,w)]=w;
return w;
}
int getw(int d,int u,int v){
int w=u+1,l=d,r=u;
while(l<=r){
int mid=(l+r)/2;
if (a[mid].v<v)l=mid+1;
else{
r=mid-1;
w=mid;
}
}
return w;
}
LL getans(int L,int R,int u){
int x=u,ls=0;
LL ans=0;
while(x){
int w1=getw(l[x]+1,r[x],L),w2=getw(l[x]+1,r[x],R+1)-1;
LL v=a[w1-1].s;
if (w1==l[x]+1)v=0;
if (w2>=w1)ans+=a[w2].s-v+LL(w2-w1+1-ls)*getdis(x,u);
ls=max(0,w2-w1+1);
x=f[x];
}
return ans;
}
int main(){
freopen("shop.in","r",stdin);
freopen("shop.out","w",stdout);
n=get(),Q=get(),A=get();
fo(i,1,n)v[i]=get();
fo(i,1,n-1){
int x=get(),y=get(),z=get();
inse(x,y,z);
inse(y,x,z);
}
dfs(ce[1]=1);
getrmq();
solve(1,0);
LL ans=0;
fo(i,1,Q){
int u=get();
int a=get(),b=get();
int L=min((a+ans)%A,(b+ans)%A),R=max((a+ans)%A,(b+ans)%A);
printf("%lld\n",ans=getans(L,R,u));
}
fclose(stdin);
fclose(stdout);
return 0;
}