RT,写的点分树,但是不知道为什么超内存了......
#include<iostream>
#include<iomanip>
#include<cstring>
#include<stack>
#include<vector>
#include<string>
#include<map>
#include<cstdlib>
#include<queue>
#include<math.h>
#include<time.h>
#include<set>
#include<cstdio>
#include<stdio.h>
#include<algorithm>
using namespace std;
template<typename T>inline void read(T &x){
x=0;
char ch=getchar();
bool fl=0;
while(ch<'0'||ch>'9') fl=(fl||ch=='-'),ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+(ch^'0'),ch=getchar();
x=fl?-x:x;
}
template<typename T>void prt(T x){
if(x>9) prt(x/10);
putchar(x%10+'0');
}
template<typename T>inline void put(char ch,T x){
if(x<0) putchar('-'),x=-x;
prt(x);
putchar(ch);
}
#define N 150005
int n,Q,A,w[N],cnt,head[N];
long long ans=0;//存答案
bool vis[N];
struct edge{
int v,nxt,val;
}e[N<<1];//链式前向星
struct father{
int x,num;
long long dis;
};
vector<father> f[N];//存一下新树
struct Son{
int age;//年龄
long long dis;
inline bool operator<(const Son &b)const{
return age<b.age;
}
};
vector<Son> s[N][3];//每个点的3棵子树
inline void add(int u,int v,int val){
e[++cnt]=(edge){v,head[u],val},head[u]=cnt;
}//建边
int get_sz(int x,int fa){//求子树大小
if(vis[x]) return 0;//已经被删了
int res=0;
for(int i=head[x];i;i=e[i].nxt)
if(e[i].v!=fa) res+=get_sz(e[i].v,x);//不能往回走
return res;
}
int get_wc(int x,int fa,int sum,int &wc){//求保持复杂度意义上的重心
if(vis[x]) return 0;//被删了
int ms=0,now=1;//最大子树(包括父节点那一颗),当前大小
for(int i=head[x];i;i=e[i].nxt){
int v=e[i].v;
if(v==fa) continue;
int sz=get_wc(v,x,sum,wc);
ms=max(ms,sz);
now+=sz;
}
ms=max(ms,sum-now);//父节点那一棵
if(ms<=sum/2) wc=x;//更新
return now;
}
void get_dist(int x,int fa,long long dist,int wc,int k,vector<Son> &p){//查找权值
if(vis[x]) return;
f[x].push_back((father){wc,k,dist});//存起来
p.push_back((Son){w[x],dist});
for(int i=head[x];i;i=e[i].nxt){
int v=e[i].v;
if(v==fa) continue;
get_dist(v,x,dist+(long long)e[i].val,wc,k,p);//继续往子树走
}
}
void calc(int x){
if(vis[x]) return;
get_wc(x,0,get_sz(x,0),x);
vis[x]=1;
int id=0;
for(int i=head[x];i;i=e[i].nxt){
int v=e[i].v;
if(vis[v]) continue;
vector<Son> &p=s[x][id];
p.push_back((Son){-1,0}),p.push_back((Son){A+1,0});//哨兵
get_dist(v,x,e[i].val,x,id,p);
id++;//子树个数增加
sort(p.begin(),p.end());//排序
for(int i=0;i<p.size();i++) p[i].dis+=p[i-1].dis;//前缀和
}
for(int i=head[x];i;i=e[i].nxt) calc(e[i].v);
}
int query(int x,int l,int r){
long long res=0;
for(int k=0;k<f[x].size();k++){
father &now=f[x][k];
if(w[now.x]>=l&&w[now.x]<=r) res+=now.dis;//在范围内
for(int i=0;i<3;i++){
if(i==now.num) continue;
vector<Son> &p=s[now.x][i];
if(p.empty()) continue;
int a=lower_bound(p.begin(),p.end(),(Son){l,-1})-p.begin();//找到左端点和右端点
int b=lower_bound(p.begin(),p.end(),(Son){r+1,-1})-p.begin();
res+=now.dis*(b-a)+p[b-1].dis-p[a-1].dis;//加上权值
}
}
for(int i=0;i<3;i++){
vector<Son> &p=s[x][i];
if(p.empty()) continue;
int a=lower_bound(p.begin(),p.end(),(Son){l,-1})-p.begin();
int b=lower_bound(p.begin(),p.end(),(Son){r+1,-1})-p.begin();
res+=p[b-1].dis-p[a-1].dis;
}
return res;
}
int main(){
read(n),read(Q),read(A);
for(int i=1;i<=n;i++) read(w[i]);
for(int i=1,u,v,w;i<n;i++) read(u),read(v),read(w),add(u,v,w),add(v,u,w);
calc(1);
for(int i=1,x,l,r;i<=Q;i++){
read(x),read(l),read(r);
l=(l+ans)%A,r=(r+ans)%A;
if(l>r) swap(l,r);
put('\n',(ans=query(x,l,r)));
}
return 0;
}