LOJ#6073. 「2017 山東一輪集訓 Day5」距離
阿新 • • 發佈:2019-01-04
題意
給了你一棵樹,然後給每個點一個新標號,每次問舊標號的點\(u,v\)路徑上的所有點對應的新標號點到舊標號點\(K\)的距離總和;
題解
這些一抹多的限制都可以轉化為偏序問題,最後只需要一下求若干個點到某點\(x\)的距離和公式\(ANS=dis[u]*t+\sum_{i=1}^tdis[i]-dis[lca(u,i)]*2\),做法跟HNOI開店那題幾乎一樣,存每條邊多算了多少次,然後套主席樹統計就行了;
#include<bits/stdc++.h> #define Fst first #define Snd second #define RG register #define mp make_pair #define mem(a,b) memset(a,b,sizeof(a)) using namespace std; typedef long long LL; typedef long double LD; typedef unsigned int UI; typedef unsigned long long ULL; template<typename T> inline void read(T& x) { char c = getchar(); bool f = false; for (x = 0; !isdigit(c); c = getchar()) { if (c == '-') { f = true; } } for (; isdigit(c); c = getchar()) { x = x * 10 + c - '0'; } if (f) { x = -x; } } template<typename T, typename... U> inline void read(T& x, U& ... y) { read(x), read(y...); } const int N=2e5+10; int n,p,Q,type,size,TIME; int head[N],dep[N],top[N],w[N],P[N],num[N],son[N],fa[N],ID[N],X[N],Y[N],root[N],np[N]; LL dis[N],sw[N],sum[N]; struct Node { int lo,ro,cnt; LL sum; }Tr[N*150]; struct Edge { int to,last,w; Edge () {} Edge (int a,int b,int c) :to(a),last(b),w(c) {} }edge[N<<1]; void ADD(int a,int b,int c) { edge[++p]=Edge(b,head[a],c); head[a]=p; edge[++p]=Edge(a,head[b],c); head[b]=p; } void DFS(int u) { num[u]=1; for(int i=head[u];i;i=edge[i].last) { int v=edge[i].to; if(v!=fa[u]) { w[v]=edge[i].w; dis[v]=dis[u]+edge[i].w; fa[v]=u; dep[v]=dep[u]+1; DFS(v); num[u]+=num[v]; if(num[son[u]]<num[v]) son[u]=v; } } } void SFD(int u,int topv) { ID[u]=++TIME; np[TIME]=u; top[u]=topv; if(!son[u]) return; SFD(son[u],topv); for(int i=head[u];i;i=edge[i].last) { int v=edge[i].to; if(!ID[v]) SFD(v,v); } } void Modify(int l,int r,int &o,int ql,int qr) { Tr[++size]=Tr[o]; o=size; Tr[o].sum+=sw[qr]-sw[ql-1]; if(ql==l&&r==qr) { ++Tr[o].cnt; return; } int mid=l+r>>1; if(qr<=mid) Modify(l,mid,Tr[o].lo,ql,qr); else if(ql>mid) Modify(mid+1,r,Tr[o].ro,ql,qr); else Modify(l,mid,Tr[o].lo,ql,mid),Modify(mid+1,r,Tr[o].ro,mid+1,qr); } LL Query(int l,int r,int x,int y,int ql,int qr,int t) { if(ql<=l&&r<=qr) { return Tr[x].sum-Tr[y].sum+1ll*t*(sw[r]-sw[l-1]); } t+=Tr[x].cnt-Tr[y].cnt; int mid=l+r>>1; LL res=0; if(ql<=mid) res=Query(l,mid,Tr[x].lo,Tr[y].lo,ql,qr,t); if(qr>mid) res+=Query(mid+1,r,Tr[x].ro,Tr[y].ro,ql,qr,t); return res; } LL Get(int u,int v,int K) { LL res=0; int cnt=0; while(top[u]!=top[v]) { if(dep[top[u]]<dep[top[v]]) swap(u,v); res+=dis[K]*(dep[u]-dep[top[u]]+1)+sum[ID[u]]-sum[ID[top[u]]-1]; X[++cnt]=root[ID[u]]; Y[cnt]=root[ID[top[u]]-1]; u=fa[top[u]]; } if(dep[u]<dep[v]) swap(u,v); res+=dis[K]*(dep[u]-dep[v]+1)+sum[ID[u]]-sum[ID[v]-1]; X[++cnt]=root[ID[u]]; Y[cnt]=root[ID[v]-1]; LL t=0; for(int i=1;i<=cnt;++i) { int x=K; while(x) { t+=Query(1,n,X[i],Y[i],ID[top[x]],ID[x],0)<<1; x=fa[top[x]]; } } return res-t; } int main() { // ios::sync_with_stdio(false); #ifdef rua freopen("GG.in","r",stdin); #endif read(type,n,Q); for(int i=1;i<n;++i) { int u,v,w; read(u,v,w); ADD(u,v,w); } DFS(1); SFD(1,1); for(int i=1;i<=n;++i) read(P[i]); for(int i=1;i<=n;++i) sum[i]=sum[i-1]+dis[P[np[i]]],sw[i]=sw[i-1]+w[np[i]]; for(int i=1;i<=n;++i) { root[i]=root[i-1]; int u=P[np[i]]; while(u) { Modify(1,n,root[i],ID[top[u]],ID[u]); u=fa[top[u]]; } } LL lastANS=0; while(Q--) { int u,v,K; read(u,v,K); u^=lastANS; v^=lastANS, K^=lastANS; printf("%lld\n",lastANS=Get(u,v,K)); lastANS*=type; } return 0; }