传送门: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; }