1. 程式人生 > >和Leo一起做愛樹上結構的好孩子之點分治 【BZOJ3784】樹上路徑

和Leo一起做愛樹上結構的好孩子之點分治 【BZOJ3784】樹上路徑

給定一個N個結點的樹,結點用正整數1..N編號。每條邊有一個正整數權值。用d(a,b)表示從結點a到結點b路邊上經過邊的權值。其中要求a < b.將這n*(n-1)/2個距離從大到小排序,輸出前M個距離值。

額這裡引入了一個新的概念:點分治序。

由於點分治是一個靜態演算法,所以對於多次點分治只需要做一次哦

記下來點分治順序和遍歷了啥(注意vector)這是因為存的總數不超過NlogN大(此時是一條長鏈)

以後訪問直接在這上面做事情就好了

於是這道題很明顯想到那道入門題:即比k小的有多少,二分最小值,求出答案

然後由於m不大,用multiset暴力算一下

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<set> 
using namespace std;
typedef int INT;
#define int long long

namespace fastIO{
    #define BUF_SIZE 100000
    #define OUT_SIZE 100000
    #define ll long long
    //fread->read
    bool IOerror=0;
    inline char nc(){
        static char buf[BUF_SIZE],*p1=buf+BUF_SIZE,*pend=buf+BUF_SIZE;
        if (p1==pend){
            p1=buf; pend=buf+fread(buf,1,BUF_SIZE,stdin);
            if (pend==p1){IOerror=1;return -1;}
            //{printf("IO error!\n");system("pause");for (;;);exit(0);}
        }
        return *p1++;
    }
    inline bool blank(char ch){return ch==' '||ch=='\n'||ch=='\r'||ch=='\t';}
    inline void read(ll &x){
        bool sign=0; char ch=nc(); x=0;
        for (;blank(ch);ch=nc());
        if (IOerror)return;
        if (ch=='-')sign=1,ch=nc();
        for (;ch>='0'&&ch<='9';ch=nc())x=x*10+ch-'0';
        if (sign)x=-x;
    }
    inline void read(double &x){
        bool sign=0; char ch=nc(); x=0;
        for (;blank(ch);ch=nc());
        if (IOerror)return;
        if (ch=='-')sign=1,ch=nc();
        for (;ch>='0'&&ch<='9';ch=nc())x=x*10+ch-'0';
        if (ch=='.'){
            double tmp=1; ch=nc();
            for (;ch>='0'&&ch<='9';ch=nc())tmp/=10.0,x+=tmp*(ch-'0');
        }
        if (sign)x=-x;
    }
    inline void read(char *s){
        char ch=nc();
        for (;blank(ch);ch=nc());
        if (IOerror)return;
        for (;!blank(ch)&&!IOerror;ch=nc())*s++=ch;
        *s=0;
    }
    inline void read(char &c){
        for (c=nc();blank(c);c=nc());
        if (IOerror){c=-1;return;}
    }
    //getchar->read
    inline void read1(int &x){
        char ch;int bo=0;x=0;
        for (ch=getchar();ch<'0'||ch>'9';ch=getchar())if (ch=='-')bo=1;
        for (;ch>='0'&&ch<='9';x=x*10+ch-'0',ch=getchar());
        if (bo)x=-x;
    }
    inline void read1(double &x){
        char ch;int bo=0;x=0;
        for (ch=getchar();ch<'0'||ch>'9';ch=getchar())if (ch=='-')bo=1;
        for (;ch>='0'&&ch<='9';x=x*10+ch-'0',ch=getchar());
        if (ch=='.'){
            double tmp=1;
            for (ch=getchar();ch>='0'&&ch<='9';tmp/=10.0,x+=tmp*(ch-'0'),ch=getchar());
        }
        if (bo)x=-x;
    }
    inline void read1(char *s){
        char ch=getchar();
        for (;blank(ch);ch=getchar());
        for (;!blank(ch);ch=getchar())*s++=ch;
        *s=0;
    }
    inline void read1(char &c){for (c=getchar();blank(c);c=getchar());}
    //scanf->read
    inline void read2(int &x){scanf("%d",&x);}
    inline void read2(double &x){scanf("%lf",&x);}
    inline void read2(char *s){scanf("%s",s);}
    inline void read2(char &c){scanf(" %c",&c);}
    inline void readln2(char *s){gets(s);}
    //fwrite->write
    struct Ostream_fwrite{
        char *buf,*p1,*pend;
        Ostream_fwrite(){buf=new char[BUF_SIZE];p1=buf;pend=buf+BUF_SIZE;}
        void out(char ch){
            if (p1==pend){
                fwrite(buf,1,BUF_SIZE,stdout);p1=buf;
            }
            *p1++=ch;
        }
        void print(int x){
            static char s[15],*s1;s1=s;
            if (!x)*s1++='0';if (x<0)out('-'),x=-x;
            while(x)*s1++=x%10+'0',x/=10;
            while(s1--!=s)out(*s1);
        }
        void println(int x){
            static char s[15],*s1;s1=s;
            if (!x)*s1++='0';if (x<0)out('-'),x=-x;
            while(x)*s1++=x%10+'0',x/=10;
            while(s1--!=s)out(*s1); out('\n');
        }
        void print(double x,int y){
            static ll mul[]={1,10,100,1000,10000,100000,1000000,10000000,100000000,
                1000000000,10000000000LL,100000000000LL,1000000000000LL,10000000000000LL,
                100000000000000LL,1000000000000000LL,10000000000000000LL,100000000000000000LL};
            if (x<-1e-12)out('-'),x=-x;x*=mul[y];
            ll x1=(ll)floor(x); if (x-floor(x)>=0.5)++x1;
            ll x2=x1/mul[y],x3=x1-x2*mul[y]; print(x2);
            if (y>0){out('.'); for (size_t i=1;i<y&&x3*mul[i]<mul[y];out('0'),++i); print(x3);}
        }
        void println(double x,int y){print(x,y);out('\n');}
        void print(char *s){while (*s)out(*s++);}
        void println(char *s){while (*s)out(*s++);out('\n');}
        void flush(){if (p1!=buf){fwrite(buf,1,p1-buf,stdout);p1=buf;}}
        ~Ostream_fwrite(){flush();}
    }Ostream;
    inline void print(int x){Ostream.print(x);}
    inline void println(int x){Ostream.println(x);}
    inline void print(char x){Ostream.out(x);}
    inline void println(char x){Ostream.out(x);Ostream.out('\n');}
    inline void print(double x,int y){Ostream.print(x,y);}
    inline void println(double x,int y){Ostream.println(x,y);}
    inline void print(char *s){Ostream.print(s);}
    inline void println(char *s){Ostream.println(s);}
    inline void println(){Ostream.out('\n');}
    inline void flush(){Ostream.flush();}
    //puts->write
    char Out[OUT_SIZE],*o=Out;
    inline void print1(int x){
        static char buf[15];
        char *p1=buf;if (!x)*p1++='0';if (x<0)*o++='-',x=-x;
        while(x)*p1++=x%10+'0',x/=10;
        while(p1--!=buf)*o++=*p1;
    }
    inline void println1(int x){print1(x);*o++='\n';}
    inline void print1(char c){*o++=c;}
    inline void println1(char c){*o++=c;*o++='\n';}
    inline void print1(char *s){while (*s)*o++=*s++;}
    inline void println1(char *s){print1(s);*o++='\n';}
    inline void println1(){*o++='\n';}
    inline void flush1(){if (o!=Out){if (*(o-1)=='\n')*--o=0;puts(Out);}}
    struct puts_write{
        ~puts_write(){flush1();}
    }_puts;
    inline void print2(int x){printf("%d",x);}
    inline void println2(int x){printf("%d\n",x);}
    inline void print2(char x){printf("%c",x);}
    inline void println2(char x){printf("%c\n",x);}
    inline void println2(){printf("\n");}
    #undef ll
    #undef OUT_SIZE
    #undef BUF_SIZE
};
using namespace fastIO;
const int N=1e5+100;
struct Front_star{
	int u,v,w,nxt;
}e[N<<2];
int cnt=0;
int first[N];
void add(int u,int v,int w){
	++cnt;
	e[cnt].u=u;
	e[cnt].v=v;
	e[cnt].w=w;
	e[cnt].nxt=first[u];
	first[u]=cnt;
}
//
vector<int> A[N*2];
int ans=0;
int n,m,K;
int All;
int root;
int siz[N];
int vis[N];
int cut[N];
int F[N];
int tot=0;
inline void Get_Root(int u,int fat){
	int now=0;
	siz[u]=1;
	for(int i=first[u];i;i=e[i].nxt){
		int v=e[i].v;
		if(v==fat||vis[v])continue;
		Get_Root(v,u);
		siz[u]+=siz[v];
		if(now<siz[v])now=siz[v];
	}
	if(now<All-siz[u])now=All-siz[u];
	F[u]=now;
	if(F[root]>now)root=u;
}
int deep[N];
int d[N];
int Record[N*3];
inline void Get_Deep(int u,int fat){
	A[tot].push_back(d[u]);
	for(int i=first[u];i;i=e[i].nxt){
		int v=e[i].v;
		if(vis[v]||v==fat)continue;
		d[v]=d[u]+e[i].w;
		Get_Deep(v,u);
	}
}
inline int Solve(int u,int dep){
	++tot;
	int Mx=A[tot].size();
	int ret=0;
	for(int l=0,r=Mx-1;l<r;){
		if(A[tot][l]+A[tot][r]>=K){
			ret+=r-l;
			--r;
		}
		else ++l;
	}
	return ret;
}
inline void DFS(int u){
	vis[u]=1;
	ans+=Solve(u,0);
	for(int i=first[u];i;i=e[i].nxt){
		int v=e[i].v;
		if(vis[v])continue;
		ans-=Solve(v,e[i].w);
		All=siz[v];
		root=0;
		Get_Root(v,0);
		DFS(root);
	}
}
//
multiset<int> S;
void Solve2(int u,int dep,int flag){
	++tot;
	int Mx=A[tot].size();
	for(int l=0,r=Mx-1;l<r;){
		if(A[tot][l]+A[tot][r]>=K){	
			for(int j=l;j<r;++j){
				int len=A[tot][j]+A[tot][r];
				if(flag==1)S.insert(len);
				else{
					S.erase(S.find(len));	
				} 	
			}
			r--;
		}
		else l++;
	}
}
void DFS2(int u){
	vis[u]=1;
	Solve2(u,0,1);
	for(int i=first[u];i;i=e[i].nxt){
		int v=e[i].v;
		if(vis[v])continue;
		Solve2(v,e[i].w,-1);
		All=siz[v];
		root=0;
		Get_Root(v,0);
		DFS2(root);
	}
} 
void Solve3(int u,int dep,int flag){
	 ++tot;
	 cut[tot]=flag;
	 d[u]=dep;
	 Get_Deep(u,0);
	 sort(A[tot].begin(),A[tot].end());
}
void DFS3(int u){
	vis[u]=1;
	Solve3(u,0,1);
	for(int i=first[u];i;i=e[i].nxt){
		int v=e[i].v;
		if(vis[v])continue;
		Solve3(v,e[i].w,-1);
		All=siz[v];
		root=0;
		Get_Root(v,0);
		DFS3(root);
	}
} 
void Pre(){
	tot=0;
	All=n;
	root=0;
	memset(vis,0,sizeof(vis));	
	Get_Root(1,0);
	DFS3(root);
}
void GetAns(int sum){
	tot=0;
	K=sum;
	All=n;
	root=0;
	memset(vis,0,sizeof(vis));	
	Get_Root(1,0);
	DFS2(root);
}
bool Check(int sum){
	int ans=0;
	K=sum;
	for(int i=1;i<=tot;++i){
		int Mx=A[i].size();
		int ret=0;
		for(int l=0,r=Mx-1;l<r;){
			if(A[i][l]+A[i][r]>=K){
				ret+=r-l;
				--r;
			}
			else ++l;			
		}
		ans=ans+cut[i]*ret;
	}
	return ans>=m;
}
//inline bool Check(int sum){
//	tot=0;
//	K=sum;
//	ans=0;
//	memset(vis,0,sizeof(vis));
//	All=n;
//	root=0;
//	Get_Root(1,0);
//	DFS(root);
//	return m<=ans;
//}
INT main(){
//	freopen("test.in","r",stdin);
//	freopen("test.out","w",stdout);
	F[0]=1e9+7;
	read(n);
	read(m);
	for(int i=1;i<n;++i){
		int u,v,w;
		read(u);
		read(v);
		read(w);
		add(u,v,w);
		add(v,u,w);
	}
	Pre();
	int l=1;
	int r=1e12+7;
	int sum=1;
	while(l<=r){
		int mid=(l+r)>>1;
		if(Check(mid)){
			l=mid+1;
			sum=mid;
		}
		else r=mid-1;
	}
	GetAns(sum);
	multiset<int>::iterator It;
	int anscnt=0;
	for(It=S.begin();It!=S.end();++It){
		Record[++anscnt]=*It;
	}
	for(int i=m;i>=1;--i)println(Record[i]);
}