zoukankan      html  css  js  c++  java
  • 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
    ",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
    ",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;
    }
    //有志者,事竟成,破釜沉舟,百二秦关终属楚;苦心人,天不负,卧薪尝胆,三千越甲可吞吴。
    

      

  • 相关阅读:
    lamp
    mysql多实例部署
    mysql进阶
    rsync
    mysql基础
    httpd
    ftp
    高级命令之awk
    NFS
    网络进阶管理
  • 原文地址:https://www.cnblogs.com/ljh2000-jump/p/6707653.html
Copyright © 2011-2022 走看看