和Leo一起做愛樹上結構的好孩子之點分治 【BZOJ3784】樹上路徑
阿新 • • 發佈:2018-12-11
給定一個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]); }