欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

2019.01.20 bzoj3784: 树上的路径(二分答案+点分治)

程序员文章站 2022-03-02 22:48:13
...

传送门
点分治好题。
题意简述:给一棵带边权的树,问所有路径中前mm大的。m300000m\le300000


思路:
网上有题解写了可以通过什么点分治序转化成超级钢琴那道题的做法蒟蒻吓得瑟瑟发抖。
然后由于我比较菜想了一个二分答案的方法。
我们二分第mm大的值,每次用点分治检验合法性。
二分完了之后我们再跑一次点分统计答案。
然后第一个二分的时候直接做是logn3log^3_n的。
考虑降下来一个loglog
我们先dfsdfs一次树把每个点作为重心的时候的所有distdist预处理下来就可以省掉一个loglog啦! 空间复杂度O(nlogn)233
代码:

#include<bits/stdc++.h>
#define ri register int
#define fi first
#define se second
using namespace std;
inline int read(){
	int ans=0;
	char ch=getchar();
	while(!isdigit(ch))ch=getchar();
	while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
	return ans;
}
typedef long long ll;
typedef pair<int,int> pii;
const int N=5e4+5,M=3e5+5;
int n,m,siz[N],msiz[N],stk[M],top=0,rt,all,Rt;
bool vis[N];
vector<pii>e[N];
vector<int>dis[N],g[N],inv[N];
ll ans;
priority_queue<int>ANS;
void getroot(int p,int fa){
	siz[p]=1,msiz[p]=0;
	for(ri i=0,v;i<e[p].size();++i){
		if(vis[v=e[p][i].fi]||v==fa)continue;
		getroot(v,p),siz[p]+=siz[v],msiz[p]=max(msiz[p],siz[v]);
	}
	msiz[p]=max(msiz[p],all-siz[p]);
	if(msiz[p]<msiz[rt])rt=p;
}
void solve(int p,int fa,int dist,vector<int>&anc){
	anc.push_back(dist);
	for(ri i=0,v;i<e[p].size();++i){
		if(vis[v=e[p][i].fi]||v==fa)continue;
		solve(v,p,dist+e[p][i].se,anc);
	}
}
void dfs(int p){
	vis[p]=1,solve(p,0,0,dis[p]);
	for(ri i=0,v;i<e[p].size();++i){
		if(vis[v=e[p][i].fi])continue;
		rt=0,all=siz[v],getroot(v,p),solve(v,p,e[p][i].se,inv[rt]),g[p].push_back(rt),dfs(rt);
	}
}
inline ll calc(vector<int>&v,int lim){
	ll ret=0;
	for(ri i=0;i<v.size();++i)ret+=v.end()-lower_bound(v.begin(),v.end(),lim-v[i]);
	return ret;
}
void Dfs(int p,int lim){
	ans+=calc(dis[p],lim);
	for(ri i=0;i<g[p].size();++i)ans-=calc(inv[g[p][i]],lim);
	if(ans>=m)return;
	for(ri i=0;i<g[p].size();++i)Dfs(g[p][i],lim);
}
inline bool check(int mid){return ans=0,Dfs(Rt,mid),ans>=m*2;}
void DFS(int p,int fa,int dist){
	stk[++top]=dist;
	for(ri i=0,v;i<e[p].size();++i)if((v=e[p][i].fi)!=fa&&!vis[v])DFS(v,p,dist+e[p][i].se);
}
inline void Solve(int p,int lim){
	stk[top=1]=0;
	for(ri i=0,len,v;i<e[p].size();++i){
		if(vis[v=e[p][i].fi])continue;
		len=top,DFS(v,p,e[p][i].se);
        for(ri j=len+1,pos;j<=top;j++){
            pos=lower_bound(stk+1,stk+len+1,lim-stk[j])-stk;
            for(ri k=pos;k<=len;++k)ANS.push(stk[j]+stk[k]);
        }
        sort(stk+len+1,stk+top+1),inplace_merge(stk+1,stk+len+1,stk+top+1);
	}
}
inline void ask(int p,int lim){vis[p]=1,Solve(p,lim);for(ri i=0;i<g[p].size();++i)ask(g[p][i],lim);}
int main(){
	n=read(),m=read();
	int L=0,R=0,K=0;
	for(ri i=1,u,v,w;i<n;++i)u=read(),v=read(),w=read(),e[u].push_back(pii(v,w)),e[v].push_back(pii(u,w)),R+=w;
	msiz[rt=0]=all=n,getroot(1,0),Rt=rt,dfs(Rt);
	for(ri i=1;i<=n;++i)sort(dis[i].begin(),dis[i].end()),sort(inv[i].begin(),inv[i].end());
	while(L<=R){
		int mid=L+R>>1;
		if(check(mid))K=mid,L=mid+1;
		else R=mid-1;
	}
	memset(vis,0,sizeof(vis)),ask(Rt,K);
	for(ri i=1;i<=m;++i){
		if(ANS.size())cout<<ANS.top()<<'\n',ANS.pop();
		else cout<<K<<'\n';
	}
	return 0;
}
相关标签: 分治