luogu P4775 [NOI2018]情報中心 線段樹合併 虛樹 樹的直徑trick
阿新 • • 發佈:2020-07-27
LINK:情報中心
神題!
寫了一下午 寫到肚子疼.
調了一晚上 調到ex
用的是網上dalao的方法 跑的挺快的.
對於鏈的暴力 我不太會kk.
直接說正解吧:
分類討論兩種情況:
1 答案的兩條鏈的LCA不重合.
2 答案的兩條鏈的LCA重合了.
會造成這兩種討論是因為我們無法確定如果LCA重合了 固定那條重合的鏈 另外一個方向上的那兩條鏈是否重合了.
其他blog裡有配圖 我就不放了直介面胡.
前者維護一下兩條鏈第一次重合的地方.
然後使用線段樹合併的時候來統計答案.
這個地方要注意細節的處理是否恰當.
後者 利用虛樹來針對某個LCA處求答案.
是在兩個支線交匯處使用樹的直徑的維護兩個端點的方法來求出最大值.
也同時注意細節的處理.
難寫難調.
code
//#include<bits/stdc++.h> #include<iostream> #include<cstdio> #include<ctime> #include<cctype> #include<queue> #include<deque> #include<stack> #include<iostream> #include<iomanip> #include<cstdio> #include<cstring> #include<string> #include<ctime> #include<cmath> #include<cctype> #include<cstdlib> #include<queue> #include<deque> #include<stack> #include<vector> #include<algorithm> #include<utility> #include<bitset> #include<set> #include<map> #define ll long long #define db double #define INF 1000000000000000000ll #define inf 100000000000000000ll #define ldb long double #define pb push_back #define put_(x) printf("%d ",x); #define get(x) x=read() #define gt(x) scanf("%d",&x) #define gi(x) scanf("%lf",&x) #define put(x) printf("%d\n",x) #define putl(x) printf("%lld\n",x) #define rep(p,n,i) for(RE int i=p;i<=n;++i) #define go(x) for(int i=lin[x],tn=ver[i];i;tn=ver[i=nex[i]]) #define fep(n,p,i) for(RE int i=n;i>=p;--i) #define vep(p,n,i) for(RE int i=p;i<n;++i) #define pii pair<int,int> #define mk make_pair #define RE register #define P 1000000007ll #define gf(x) scanf("%lf",&x) #define pf(x) ((x)*(x)) #define uint unsigned long long #define ui unsigned #define EPS 1e-10 #define sq sqrt #define S second #define F first #define mod 1000000007 #define r(x) t[x].r #define l(x) t[x].l #define mx1(x) t[x].mx1 #define mx2(x) t[x].mx2 #define max(x,y) ((x)<(y)?y:x) using namespace std; char *fs,*ft,buf[1<<15]; inline char gc() { return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++; } inline int read() { RE int x=0,f=1;RE char ch=gc(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=gc();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=gc();} return x*f; } inline ll Read() { RE ll x=0,f=1;RE char ch=gc(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=gc();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=gc();} return x*f; } const int MAXN=50010; int n,m,len,T,maxx=50000<<1,id,cnt,rt,top,now; int Log[MAXN<<1],dfn[MAXN],q[MAXN<<2],f[MAXN<<1][20],root[MAXN],d[MAXN]; int lin[MAXN],ver[MAXN<<1],nex[MAXN<<1],e[MAXN<<1],fa[MAXN],vis[MAXN]; ll dis[MAXN],ans; vector<pair<int,ll> >g[MAXN]; inline void add(int x,int y,int z){ver[++len]=y;nex[len]=lin[x];lin[x]=len;e[len]=z;} struct wy{int l,r;ll mx1,mx2;}t[MAXN*40]; struct jl{int x,y;ll z;jl(){}jl(int _a,int _b,ll _z){x=_a;y=_b;z=_z;}}; struct xn { jl a,b;ll d; xn(){} xn(jl _a,jl _b,ll _d){a=_a;b=_b;d=_d;} inline ll operator <(xn b){return d<b.d;} }w[MAXN]; vector<jl>s[MAXN]; inline void dfs(int x,int father) { f[++cnt][0]=x;dfn[x]=cnt;d[x]=d[father]+1;fa[x]=father; go(x)if(tn!=fa[x]) dis[tn]=dis[x]+e[i],dfs(tn,x),f[++cnt][0]=x; } inline int cmp(int x,int y){return d[x]<d[y]?x:y;} inline int LCA(int x,int y) { x=dfn[x];y=dfn[y]; if(x>y)swap(x,y); int z=Log[y-x+1]; return cmp(f[x][z],f[y-(1<<z)+1][z]); } inline bool cmp1(int x,int y){return dfn[x]<dfn[y];} inline ll dist(int x,int y){return dis[x]+dis[y]-dis[LCA(x,y)]*2;} struct solve1//solve 1. { inline void pushup(int p) { mx1(p)=max(mx1(l(p)),mx1(r(p))); mx2(p)=max(mx2(l(p)),mx2(r(p))); } inline void insert(int &p,int l,int r,int x,ll c1,ll c2) { if(!p)p=++id,t[p]=t[0]; if(l==r){mx1(p)=max(mx1(p),c1);mx2(p)=max(mx2(p),c2);return;} int mid=(l+r)>>1; if(x<=mid)insert(l(p),l,mid,x,c1,c2); else insert(r(p),mid+1,r,x,c1,c2); pushup(p); } inline int merge(int l,int r,int x,int y) { if(!x||!y)return x|y; if(l==r) { mx1(x)=max(mx1(x),mx1(y)); mx2(x)=max(mx2(y),mx2(x)); return x; } ans=max(ans,mx1(l(x))+mx2(r(y))-dis[now]); ans=max(ans,mx1(l(y))+mx2(r(x))-dis[now]); int mid=(l+r)>>1; l(x)=merge(l,mid,l(x),l(y)); r(x)=merge(mid+1,r,r(x),r(y)); pushup(x);return x; } inline void change(int &p,int l,int r,int x) { if(!p)return; if(l==r){p=0;return;} int mid=(l+r)>>1; if(x<=mid)change(l(p),l,mid,x); else change(r(p),mid+1,r,x); if(!l(p)&&!r(p))p=0; else pushup(p); } inline void dfs(int x) { go(x)if(tn!=fa[x]) { dfs(tn); change(root[tn],1,n,d[x]);now=x; root[x]=merge(1,n,root[x],root[tn]); } now=x; vep(0,(int)g[x].size(),j) { int r=0; insert(r,1,n,d[g[x][j].F],g[x][j].S,g[x][j].S+dis[g[x][j].F]); root[x]=merge(1,n,root[x],r); } } inline void solve() { dfs(1); rep(1,n,i)root[i]=0,g[i].clear();id=0; } }S1; struct solve2 { inline xn calc(jl a,jl b) { ll dd=dist(a.x,b.x)+a.z+b.z; ans=max(ans,dd/2-dis[now]); return xn(a,b,dd); } inline void merge(xn &A,xn &B) { if(A.d==-INF){A=B;B.d=-INF;return;} if(B.d==-INF)return; if(now!=rt) { xn W=max(calc(A.a,B.a),calc(A.a,B.b)); W=max(W,calc(A.b,B.a));W=max(W,calc(A.b,B.b)); A=max(A,B);A=max(A,W); } B.d=-INF; } inline void calc() { int cc=0;top=0; vep(0,(int)s[rt].size(),j) { q[++top]=s[rt][j].x;q[++top]=s[rt][j].y; jl a=jl(q[top-1],0,s[rt][j].z+dis[q[top]]); jl b=jl(q[top],0,s[rt][j].z+dis[q[top-1]]); xn A=xn(a,a,a.z<<1);xn B=xn(b,b,b.z<<1); merge(w[now=q[top]],A);merge(w[now=q[top-1]],B); } sort(q+1,q+1+top,cmp1); vis[++cc]=rt;q[0]=rt; rep(1,top,i) { if(q[i]==q[i-1])continue; if(cc==1){vis[++cc]=q[i];continue;} int lca=LCA(q[i],vis[cc]); while(cc>1&&d[lca]<=d[vis[cc-1]]) { merge(w[now=vis[cc-1]],w[vis[cc]]); --cc; } if(vis[cc]!=lca)merge(w[now=lca],w[vis[cc]]),vis[cc]=lca; vis[++cc]=q[i]; } while(cc>1) { merge(w[now=vis[cc-1]],w[vis[cc]]); --cc; } w[rt].d=-INF; //rep(1,top,i)if(w[q[i]].d!=-INF)cout<<"ww"<<endl; } inline void solve() { rep(1,n,i)w[i].d=-INF; rep(1,n,i)if(s[i].size()>1)rt=i,calc(); rep(1,n,i)s[i].clear(); } }S2; int main() { //freopen("1.in","r",stdin); get(T);mx1(0)=mx2(0)=-INF; rep(2,maxx,i)Log[i]=Log[i>>1]+1; while(T--) { ans=-INF;cnt=0;len=0; rep(1,n,i)lin[i]=0; get(n); rep(2,n,i) { int get(x),get(y),get(z); add(x,y,z);add(y,x,z); } dfs(1,0); rep(1,Log[cnt],j) rep(1,cnt-(1<<j)+1,i)f[i][j]=cmp(f[i][j-1],f[i+(1<<(j-1))][j-1]); //put(dis[4]); get(m); rep(1,m,i) { int get(x),get(y);ll z=Read(); if(x==y)continue; int lca=LCA(x,y);ll cc=dist(x,y)-z; if(x!=lca)g[x].pb(mk(lca,cc)); if(y!=lca)g[y].pb(mk(lca,cc)); s[lca].pb(jl(x,y,cc-z)); } S1.solve(); S2.solve(); //cout<<ans<<' '<<-INF<<' '<<(ans<-INF)<<endl; if(ans<-inf)puts("F"); else putl(ans); } return 0; }