BZOJ2117 [2010国家集训队]Crash的旅游计划
本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作。
本文作者:ljh2000
作者博客:http://www.cnblogs.com/ljh2000-jump/
转载请注明出处,侵权必究,保留最终解释权!
题目链接:BZOJ2117
正解:动态树分治
解题报告:
考虑维护一棵动态树分治的结构树,因为是树高严格$log$的,所以就可以暴力往上跳了。
先建出这棵树,然后维护树分治结构中的所有点到分治重心的距离,以及到分治重心的分治结构父亲的距离。
对于每个点,二分答案,然后计算与他距离$<=mid$的点的个数,往上跳的时候加加减减,容斥一下计算答案。
注意动态树分治的结构与原树大不相同!计算贡献、距离什么的都要仔细考虑!
//It is made by ljh2000 //有志者,事竟成,破釜沉舟,百二秦关终属楚;苦心人,天不负,卧薪尝胆,三千越甲可吞吴。 #include <algorithm> #include <iostream> #include <cstring> #include <vector> #include <cstdio> #include <string> #include <queue> #include <cmath> #include <ctime> #define lc root<<1 #define rc root<<1|1 #define rep(i,j,k) for(int i=j;i<=k;i++) #define reg(i,x) for(int i=first[x];i;i=next[i]) using namespace std; typedef long long LL; const int MAXN = 200011; const int MAXM = 400011; int n,k,ecnt,first[MAXN],to[MAXM],next[MAXM],w[MAXM],S,minl,size[MAXN],tot,father[MAXN],dis[MAXN],dis2[MAXN]; bool vis[MAXN]; vector<int>D1[MAXN],D2[MAXN]; inline void link(int x,int y,int z){ next[++ecnt]=first[x]; first[x]=ecnt; to[ecnt]=y; w[ecnt]=z; } inline int getint(){ int w=0,q=0; char c=getchar(); while((c<'0'||c>'9') && c!='-') c=getchar(); if(c=='-') q=1,c=getchar(); while (c>='0'&&c<='9') w=w*10+c-'0',c=getchar(); return q?-w:w; } namespace jump{ int f[MAXN][20],deep[MAXN],g[MAXN][20]; inline void dfs(int x,int fa){ reg(i,x) { int v=to[i]; if(v==fa) continue; deep[v]=deep[x]+1; g[v][0]=w[i]; f[v][0]=x; dfs(v,x); } } inline void Init(){ deep[1]=1; dfs(1,0); for(int j=1;j<=19;j++) for(int i=1;i<=n;i++) f[i][j]=f[f[i][j-1]][j-1],g[i][j]=g[i][j-1]+g[f[i][j-1]][j-1];} inline int getdis(int x,int y){ if(x==y) return 0; if(deep[x]<deep[y]) swap(x,y);//!!! int tot=0,t=0; while((1<<t)<=deep[x]) t++; t--; for(int i=t;i>=0;i--) if(deep[x]-(1<<i)>=deep[y]) tot+=g[x][i],x=f[x][i]; if(x==y) return tot; for(int i=t;i>=0;i--) if(f[x][i]!=f[y][i]) tot+=g[x][i],tot+=g[y][i],x=f[x][i],y=f[y][i]; tot+=g[x][0]; tot+=g[y][0]; return tot; } } inline void calcw(int x,int fa){ size[x]=1; tot++; for(int i=first[x];i;i=next[i]){ int v=to[i]; if(v==fa || vis[v]) continue; calcw(v,x); size[x]+=size[v]; } } inline void dp(int x,int fa){ int maxs=0; for(int i=first[x];i;i=next[i]){ int v=to[i]; if(v==fa || vis[v]) continue; dp(v,x); maxs=max(maxs,size[v]); } maxs=max(maxs,tot-size[x]); if(maxs<minl) minl=maxs,S=x; } inline void getrt(int &x){ tot=0; calcw(x,0); S=0; minl=n+1; dp(x,0); x=S; } inline void dfs(int x,int fa,int nowrt,int lei){ D2[nowrt].push_back(dis[x]); dis2[x]=dis[x]; dis[x]=lei; D1[nowrt].push_back(lei); for(int i=first[x];i;i=next[i]) { int v=to[i]; if(v==fa || vis[v]) continue; dfs(v,x,nowrt,lei+w[i]); } } inline int solve(int x){ getrt(x); vis[x]=1; dfs(x,0,x,0); if(tot==1) return x; for(int i=first[x];i;i=next[i]) { int v=to[i]; if(vis[v]) continue; father[solve(v)]=x;//!!! } return x; } inline bool calc(int x,int val){ int tot=0,savval=val,savx=x,last=0; while(x) { val=savval-jump::getdis(x,savx); //if(val<0) return false;//!!! if(last) { tot-=upper_bound(D2[last].begin(),D2[last].end(),val)-D2[last].begin(); } tot+=upper_bound(D1[x].begin(),D1[x].end(),val)-D1[x].begin(); if(tot>k) return true; /*if(father[x]) { //printf("---%d\n",upper_bound(D2[x].begin(),D2[x].end(),val)-D2[x].begin()); tot-=upper_bound(D2[x].begin(),D2[x].end(),val)-D2[x].begin(); }*/ last=x; x=father[x]; } return false; } inline void getans(int x){ int l=0,r=(1<<30)-1,mid; int ans=0; while(l<=r) { mid=(l+r)>>1; if(calc(x,mid)) r=mid-1,ans=mid; else l=mid+1; } printf("%d\n",ans); } inline void work(){ n=getint(); k=getint(); int x,y,z; for(int i=1;i<n;i++) { x=getint(); y=getint(); z=getint(); link(x,y,z); link(y,x,z); } jump::Init(); solve(1); for(int i=1;i<=n;i++) sort(D1[i].begin(),D1[i].end()),sort(D2[i].begin(),D2[i].end()); for(int i=1;i<=n;i++) getans(i); } int main() { #ifndef ONLINE_JUDGE freopen("2117.in","r",stdin); freopen("2117.out","w",stdout); #endif work(); return 0; } //有志者,事竟成,破釜沉舟,百二秦关终属楚;苦心人,天不负,卧薪尝胆,三千越甲可吞吴。
本文作者:ljh2000
作者博客:http://www.cnblogs.com/ljh2000-jump/
转载请注明出处,侵权必究,保留最终解释权!