[WC2010]重建計劃(長鏈剖分版)
阿新 • • 發佈:2019-04-06
www solution www. eight segment std 假設 距離 include
傳送門
Description
Solution
時隔多年,補上了這題的長鏈剖分寫法
感覺比點分治要好寫的多
我們假設\(pos\)是當前點的\(dfn\),它距離所在鏈的底端的邊的數量是\(len\),距離是\(siz\)
那麽我們要求得\(g[pos...pos+len]\)
其中\(g[pos+i]+siz\)表示的是當前點往下長度為\(i\)的最長鏈的大小
初始情況下,\(g[pos]=-siz[pos]\)
為什麽要這麽寫呢?
因為轉移重兒子的時候,我們直接把數組右移了一位,這樣子定義使得原先的值仍然有意義
考慮如何轉移?
對於一個輕兒子,\(dfn\)為\(pv\)
那麽\(當前點,輕兒子g[pos+j+1]\leftarrow siz[pv]+g[pv+j]+w(當前點,輕兒子)-siz\)
考慮如何更新答案
對於\(lca\)為當前點的鏈
首先計算一個端點就是當前點的:\((g[pos+i])_{min}+siz\)
然後是兩個端點分別處於不同子樹的
枚舉一個輕兒子子樹內的鏈長:\(當前點,輕兒子(g[pos+i])_{min}+siz+(siz[pv]+g[pv+j])+(w(當前點,輕兒子))\)
求min的部分用線段樹優化
這題卡一定的常數,不知道為什麽,std::max/min要比手寫的快
Code?
#include<bits/stdc++.h> #define ll long long #define reg register #define ri reg int i using namespace std; inline int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();} return x*f; } const int MN=1e5+5; const double eps=1e-4,inf=0x3f3f3f3f; double siz[MN],g[MN],ans,mid; struct edge{int to,w,nex;}e[MN<<1];int hr[MN],en; inline void ins(int x,int y,int w) { e[++en]=(edge){y,w,hr[x]};hr[x]=en; e[++en]=(edge){x,w,hr[y]};hr[y]=en; } int dfn[MN],len[MN],mx[MN],w[MN],ind,n,L,R; struct SegmentTree { #define ls (x<<1) #define rs (x<<1|1) #define Mid ((l+r)>>1) double t[MN<<2]; inline void clear(){for(ri=0;i<(MN<<2);++i)t[i]=-inf;} void Modify(int x,int l,int r,int a,double val) { if(l==r) return(void)(t[x]=max(t[x],val)); if(a<=Mid) Modify(ls,l,Mid,a,val); else Modify(rs,Mid+1,r,a,val); t[x]=max(t[ls],t[rs]); } double Query(int x,int l,int r,int a,int b) { if(l==a&&r==b) return t[x];if(a>b)return -inf; if(b<=Mid) return Query(ls,l,Mid,a,b); if(a>Mid) return Query(rs,Mid+1,r,a,b); return max(Query(ls,l,Mid,a,Mid),Query(rs,Mid+1,r,Mid+1,b)); } }T; void dfs(int x,int f=0) { for(ri=hr[x];i;i=e[i].nex)if(e[i].to^f) { dfs(e[i].to,x); if(len[e[i].to]>=len[mx[x]]) mx[x]=e[i].to,w[x]=e[i].w; if(len[e[i].to]+1>len[x]) len[x]=len[e[i].to]+1; } } void solve(int x,int f=0) { if(!dfn[x]) dfn[x]=++ind; reg int i,j,pos=dfn[x]; if(mx[x]) solve(mx[x],x),siz[pos]=siz[pos+1]+w[x]-mid; T.Modify(1,1,n,pos,g[pos]=-siz[pos]); if(L<=len[x]) { double tmp=T.Query(1,1,n,pos+L,pos+min(len[x],R)); ans=max(ans,tmp+siz[pos]); } for(i=hr[x];i;i=e[i].nex)if(e[i].to!=f&&e[i].to!=mx[x]) { solve(e[i].to,x);reg int pv=dfn[e[i].to]; for(j=0;j<=len[e[i].to];++j) { double tmp=T.Query(1,1,n,pos+max(0,L-j-1),pos+min(len[x],R-j-1)); ans=max(ans,tmp+siz[pv]+siz[pos]+g[pv+j]+e[i].w-mid); } for(j=0;j<=len[e[i].to];++j) { double tmp=siz[pv]+g[pv+j]+e[i].w-mid-siz[pos]; if(tmp>g[pos+j+1]) T.Modify(1,1,n,pos+j+1,g[pos+j+1]=tmp); } } } bool check(){T.clear();ans=-inf;solve(1);return ans>=eps;} int main() { n=read();L=read();R=read(); reg int i,x,y; for(i=1;i<n;++i) x=read(),y=read(),ins(x,y,read()); dfs(1);double l=0.,r=1e6; for(i=1;i<=40;++i) { if(l+eps>=r) break; mid=(l+r)/2.; if(check()) l=mid;else r=mid; } printf("%.3lf",l); return 0; }
Blog來自PaperCloud,未經允許,請勿轉載,TKS!
[WC2010]重建計劃(長鏈剖分版)