题面在这里
题意
一棵(n)个节点的树,树上每个节点有一个权值(v[i]),边有边权(w[e]),
给出(Q)次询问,对于每次询问((u,L,R)),求点权在([L,R])的点到(u)的路径长度之和
强制在线~
数据范围
sol
不考虑点权,如果仅求所有点到(u)的距离该怎么做?
(ecausesum_{v=1}^{n}dist(u,v)=sum_{v=1}^{n}dep[v]+n imes dep[u]-2 imessum_{v=1}^{n}dep[lca(u,v)]),
(sum_{v=1}^{n}dep[v]),(n imes dep[u])都可以利用前缀和求出;
瓶颈在于求(sum_{v=1}^{n}dep[lca(u,v)]);
如何求?首先将所有节点进行路径覆盖((v,rt)),
最后答案即为(u)到(rt)的路径(()边权( imes)覆盖次数())之和
这个可以使用树链剖分做
当有点权([L,R])的限制的时候离散化+主席树做前缀和即可
时间和空间应该都是(O(nlog^2n))的...
线段树标记永久化
第一次写居然是在主席树上...
主要思想是修改时直接在对应的节点打(lazy),询问时直接把标记往下带
具体实现:
修改
假设我们现在打了一个(modify(l,r,x,y))函数,
询问区间为([x,y]),目前线段树的区间为([l,r]);
当到达底部((xle l && r le y))的时候,我们直接打(lazy)(不需要加(sum))就可以了
回溯上来的时候,由于打(lazy)节点的祖先节点在询问时访问不到这个(lazy),
我们就需要把打了这个(lazy)后对祖先节点的影响直接加到祖先节点上
如果我们需要支持区间加,像这样
#define ls (i<<1)
#define rs (i<<1|1)
#define mid ((l+r)>>1)
int sum[N<<4],lazy[N<<4];
void modify(int i,int l,int r,int x,int y,int add){
//这个是线段树版本,主席树的下面有
if(x<=l&&r<=y){lazy[i]+=add;return;}
sum[i]+=add*(y-x+1);
if(y<=mid)modify(ls,l,mid,x,y,add);
else if(x>mid)modify(rs,mid+1,r,x,y,add);
else modify(ls,l,mid,x,mid,add),modify(rs,mid+1,r,mid+1,y,add);
}
询问
知道(lazy)标记是怎么来的就好办了,
我们知道此时一个线段树节点的(lazy)标记是其所有祖先(lazy)标记的总和,
于是一路下来加好(lazy),当到达底部((xle l && r le y))的时候,
把之前所有(lazy)的和( imes)底部节点的权值就可以了
如果我们需要支持区间求和(爆精度什么的我才不管呢),像这样
#define ls (i<<1)
#define rs (i<<1|1)
#define mid ((l+r)>>1)
int sum[N<<4],lazy[N<<4];
int query(int i,int l,int r,int x,int y){
//这个是线段树版本,主席树的下面有
RG int ret=sum[i];
if(x<=l&&r<=y)return ret+lz[i]*(y-x+1);
if(y<=mid)return ret+query(ls,l,mid,x,y);
else if(x>mid)return ret+query(rs,mid+1,r,x,y);
else return ret+query(ls,l,mid,x,mid)+query(rs,mid+1,r,mid+1,y);
}
代码
#include<bits/stdc++.h>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<iomanip>
#include<cstring>
#include<complex>
#include<vector>
#include<cstdio>
#include<string>
#include<bitset>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#define mp make_pair
#define pub push_back
#define puf push_front
#define pob pop_back
#define pof pop_front
#define RG register
#define il inline
using namespace std;
typedef unsigned long long ull;
typedef vector<int>VI;
typedef long long ll;
typedef double dd;
const dd eps=1e-10;
const int mod=1e8;
const int N=150010;
const int M=150*N;
il ll read(){
RG ll data=0,w=1;RG char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
if(ch=='-')w=-1,ch=getchar();
while(ch<='9'&&ch>='0')data=data*10+ch-48,ch=getchar();
return data*w;
}
il void file(){
freopen("shop10.in","r",stdin);
freopen("a.out","w",stdout);
}
struct node{
int x,y;
bool operator <(const node b)const{
if(x==b.x)return y<b.y;
return x<b.x;
}
}a[N];
int head[N],nxt[N<<1],to[N<<1],val[N<<1],cnte;
ll sumE[N];
il void add(int u,int v,int w){
to[++cnte]=v;
nxt[cnte]=head[u];
val[cnte]=w;
head[u]=cnte;
}
int n,Q,A,rt[N],cnt;
struct tree{int ls,rs,tag;ll sum;}t[M];
int fa[N],sz[N],son[N];ll dep[N];
void dfs1(int u,int f){
fa[u]=f;sz[u]=1;
for(RG int i=head[u];i;i=nxt[i]){
RG int v=to[i];if(v==fa[u])continue;
dep[v]=dep[u]+val[i];dfs1(v,u);
sz[u]+=sz[v];if(sz[v]>sz[son[u]])son[u]=v;
}
}
int dfn[N],top[N];
void dfs2(int u,int tp){
top[u]=tp;dfn[u]=++cnt;
sumE[cnt]=dep[u]-dep[fa[u]];
if(son[u])dfs2(son[u],tp);
for(RG int i=head[u];i;i=nxt[i]){
RG int v=to[i];if(v==fa[u]||v==son[u])continue;
dfs2(v,v);
}
}
#define mid ((l+r)>>1)
void build(int &i,int l,int r){
i=++cnt;if(l==r)return;
build(t[i].ls,l,mid);build(t[i].rs,mid+1,r);
}
void modify(int &i,int l,int r,int x,int y){
t[++cnt]=t[i];i=cnt;
if(l==x&&r==y){t[i].tag++;return;}
t[i].sum+=sumE[y]-sumE[x-1];
if(y<=mid)modify(t[i].ls,l,mid,x,y);
else if(x>mid)modify(t[i].rs,mid+1,r,x,y);
else modify(t[i].ls,l,mid,x,mid),modify(t[i].rs,mid+1,r,mid+1,y);
}
ll query(int &i,int l,int r,int x,int y){
RG ll ret=1ll*t[i].tag*(sumE[y]-sumE[x-1]);
if(l==x&&r==y)return ret+t[i].sum;
if(y<=mid)return ret+query(t[i].ls,l,mid,x,y);
else if(x>mid)return ret+query(t[i].rs,mid+1,r,x,y);
else return ret+query(t[i].ls,l,mid,x,mid)+query(t[i].rs,mid+1,r,mid+1,y);
}
ll sumdis[N],ans;
il ll ask(int k,int u){
ll ret=0;
while(top[u]^1)
ret+=query(rt[k],1,n,dfn[top[u]],dfn[u]),u=fa[top[u]];
ret+=query(rt[k],1,n,1,dfn[u]);return ret;
}
int main()
{
n=read();Q=read();A=read();
for(RG int i=1;i<=n;i++)a[i]=(node){read(),i};
sort(a+1,a+n+1);
for(RG int i=1,aa,b,c;i<n;i++){
aa=read();b=read();c=read();
add(aa,b,c);add(b,aa,c);
}
dfs1(1,0);dfs2(1,1);cnt=0;build(rt[0],1,n);
for(RG int i=1;i<=n;i++)
sumE[i]+=sumE[i-1],sumdis[i]+=sumdis[i-1]+dep[a[i].y];
for(RG int i=1;i<=n;i++){
RG int u=a[i].y;rt[i]=rt[i-1];
while(top[u]^1)modify(rt[i],1,n,dfn[top[u]],dfn[u]),u=fa[top[u]];
modify(rt[i],1,n,1,dfn[u]);
}
for(RG int i=1,u,l,r;i<=Q;i++){
u=read();l=(read()+ans)%A;r=(read()+ans)%A;
if(l>r)swap(l,r);
l=lower_bound(a+1,a+n+1,(node){l,0})-a;
r=upper_bound(a+1,a+n+1,(node){r,n})-a-1;
printf("%lld
",ans=dep[u]*(r-l+1)+sumdis[r]-sumdis[l-1]-2*(ask(r,u)-ask(l-1,u)));
}
return 0;
}
zsy大佬是最强的!!!