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/
转载请注明出处,侵权必究,保留最终解释权!

浙公网安备 33010602011771号