loj6145. 「2017 山東三輪集訓 Day7」Easy
阿新 • • 發佈:2020-07-20
題解:由於區間內每個點和\(x\)的lca都不盡相同,我們很難用\(dep_x+dep_y-2\times dep_{lca}\)來進行求解。於是考慮點分治,把詢問離線下來,掛在點\(x\)上。
發現問題變得很簡單:我們只需要掃一遍分治中心的所有兒子,先線上段樹上查一下區間離它最遠的點的距離,然後再把自己加進線段樹裡就行了,注意正反要各做一遍。由於每個點只會涉及到log次線段樹的單點修改、區間查詢,時間複雜度就是\(O(nlog^2n)\)。
如果本題強制線上,那麼只需要把所有分治中心的線段樹(或者平衡樹)都建出來,然後在點分樹上跳father,注意查的時候要減去它所在子樹線上段樹上的貢獻就行了,這個東西對於做過動態點分治的大神們應該不陌生。
時間複雜度:\(O(nlog^2n)\)。
程式碼:
#include<bits/stdc++.h> using namespace std; #define re register int #define F(x,y,z) for(re x=y;x<=z;x++) #define FOR(x,y,z) for(re x=y;x>=z;x--) typedef long long ll; #define I inline void #define IN inline int #define C(x,y) memset(x,y,sizeof(x)) #define STS system("pause") template<class D>I read(D &res){ res=0;register D g=1;register char ch=getchar(); while(!isdigit(ch)){ if(ch=='-')g=-1; ch=getchar(); } while(isdigit(ch)){ res=(res<<3)+(res<<1)+(ch^48); ch=getchar(); } res*=g; } const int INF=1e9+7; struct E{ int to,nt,w; }e[202000]; struct P{ int x,y,id; P(int _x=0,int _y=0,int _id=0){x=_x;y=_y;id=_id;} }; #define T e[k].to int n,m,rot,head[101000],tot,vis[101000],siz[101000],mx[101000],N,maxi,root,ans[101000]; vector<int>G[101000],tmp; vector<P>t[101000]; struct Segtree{ int tr[404000],laz[404000]; #define all 1,1,n #define lt k<<1,l,mid #define rt k<<1|1,mid+1,r I add(int k){tr[k]=INF;laz[k]=1;} I push_down(int k){ add(k<<1),add(k<<1|1);laz[k]=0; } I modi(int k,int l,int r,int x,int w){ if(l==r)return tr[k]=w,void(); if(laz[k])push_down(k); re mid=(l+r)>>1; if(x<=mid)modi(lt,x,w); else modi(rt,x,w); tr[k]=min(tr[k<<1],tr[k<<1|1]); } IN ques(int k,int l,int r,int x,int y){ if(x>r||y<l)return INF; if(x<=l&&r<=y)return tr[k]; if(laz[k])push_down(k); re mid=(l+r)>>1; return min(ques(lt,x,y),ques(rt,x,y)); } }S; I add(int x,int y,int w){ e[++tot].to=y;e[tot].nt=head[x];head[x]=tot;e[tot].w=w; } I findroot(int x,int fa){ siz[x]=1;mx[x]=0; for(re k=head[x];k!=-1;k=e[k].nt){ if(T==fa||vis[T])continue; findroot(T,x);mx[x]=max(mx[x],siz[T]); siz[x]+=siz[T]; } mx[x]=max(mx[x],N-siz[x]); if(mx[x]<maxi)maxi=mx[x],root=x; } I D_1(int x,int fa){ siz[x]=1; for(re k=head[x];k!=-1;k=e[k].nt){ if(T==fa||vis[T])continue; D_1(T,x);siz[x]+=siz[T]; } } I divided(int x,int fa){ if(fa)G[fa].emplace_back(x); D_1(x,0);vis[x]=1; for(re k=head[x];k!=-1;k=e[k].nt){ if(T==fa||vis[T])continue; N=siz[T];maxi=INF; findroot(T,x);divided(root,x); } } I D_2(int x,int fa,int dist){ for(auto d:t[x])ans[d.id]=min(ans[d.id],S.ques(all,d.x,d.y)+dist); for(re k=head[x];k!=-1;k=e[k].nt){ if(T==fa||vis[T])continue; D_2(T,x,dist+e[k].w); } } I D_3(int x,int fa,int dist){ S.modi(all,x,dist); for(re k=head[x];k!=-1;k=e[k].nt){ if(T==fa||vis[T])continue; D_3(T,x,dist+e[k].w); } } I solve(int x){ S.add(1);S.modi(all,x,0);tmp.clear(); for(re k=head[x];k!=-1;k=e[k].nt){ if(vis[T])continue; tmp.emplace_back(k); D_2(T,x,e[k].w);D_3(T,x,e[k].w); } reverse(tmp.begin(),tmp.end()); S.add(1);S.modi(all,x,0); for(auto k:tmp)D_2(T,x,e[k].w),D_3(T,x,e[k].w); for(auto d:t[x])ans[d.id]=min(ans[d.id],S.ques(all,d.x,d.y)); vis[x]=1; for(auto d:G[x])solve(d); } int main(){ read(n);C(head,-1);tot=-1; re X,Y,W; F(i,1,n-1){ read(X);read(Y);read(W); add(X,Y,W);add(Y,X,W); } N=n;maxi=INF;findroot(1,0);rot=root;divided(root,0); read(m); F(i,1,m){ read(X);read(Y);read(W); t[W].emplace_back(P(X,Y,i));ans[i]=INF; } C(vis,0);solve(rot); F(i,1,m)printf("%d\n",ans[i]); return 0; }