BZOJ 2117: [2010国家集训队]Crash的旅游计划 动态点分治+二分
感觉现在写点分治可快了~
二分答案,就可以将求第 $k$ 大转换成一个判断问题,直接拿点分树判断一下就行了.
#include <cstdio> #include <vector> #include <algorithm> #define N 100004 #define setIO(s) freopen(s".in","r",stdin) using namespace std; int n,edges,K; int hd[N],to[N<<1],nex[N<<1],val[N<<1]; void add(int u,int v,int c) { nex[++edges]=hd[u],hd[u]=edges,to[edges]=v,val[edges]=c; } namespace tree { int size[N],son[N],fa[N],top[N],dep[N],dis[N]; void dfs1(int u,int ff) { fa[u]=ff,size[u]=1; for(int i=hd[u];i;i=nex[i]) if(to[i]!=ff) { dep[to[i]]=dep[u]+1,dis[to[i]]=dis[u]+val[i]; dfs1(to[i],u); size[u]+=size[to[i]]; if(size[to[i]]>size[son[u]]) son[u]=to[i]; } } void dfs2(int u,int tp) { top[u]=tp; if(son[u]) dfs2(son[u],tp); for(int i=hd[u];i;i=nex[i]) if(to[i]!=fa[u]&&to[i]!=son[u]) dfs2(to[i],to[i]); } int LCA(int x,int y) { while(top[x]!=top[y]) dep[top[x]]>dep[top[y]]?x=fa[top[x]]:y=fa[top[y]]; return dep[x]<dep[y]?x:y; } int Dis(int x,int y) { return dis[x]+dis[y]-(dis[LCA(x,y)]<<1); } }; vector<int>F[N],G[N]; int root,sn; int mx[N],size[N],vis[N],Fa[N]; void dfs(int u,int ff) { size[u]=1; for(int i=hd[u];i;i=nex[i]) if(!vis[to[i]]&&to[i]!=ff) dfs(to[i],u),size[u]+=size[to[i]]; } void getroot(int u,int ff) { size[u]=1,mx[u]=0; for(int i=hd[u];i;i=nex[i]) if(to[i]!=ff&&!vis[to[i]]) getroot(to[i],u),size[u]+=size[to[i]],mx[u]=max(mx[u],size[to[i]]); mx[u]=max(mx[u],sn-size[u]); if(mx[u]<mx[root]) root=u; } void calc(int u,int ff,int dep,int rt) { F[rt].push_back(dep); if(Fa[rt]) G[rt].push_back(tree::Dis(Fa[rt], u)); for(int i=hd[u];i;i=nex[i]) if(to[i]!=ff&&!vis[to[i]]) calc(to[i],u,dep+val[i],rt); } void prepare(int u) { vis[u]=1; calc(u,0,0,u); F[u].push_back(1000000004); sort(F[u].begin(),F[u].end()); if(Fa[u]) { G[u].push_back(1000000004); sort(G[u].begin(),G[u].end()); } for(int i=hd[u];i;i=nex[i]) if(!vis[to[i]]) dfs(to[i],u),sn=size[to[i]],root=0,getroot(to[i],u),Fa[root]=u,prepare(root); } int query(int u,int k) { int U=u, re=upper_bound(F[u].begin(),F[u].end(),k)-F[u].begin()-1; for(;Fa[u];u=Fa[u]) { int dis=tree::Dis(Fa[u],U); if(dis<=k) { re+=(upper_bound(F[Fa[u]].begin(),F[Fa[u]].end(),k-dis)-F[Fa[u]].begin()); re-=(upper_bound(G[u].begin(),G[u].end(),k-dis)-G[u].begin()); } } return re; } int main() { int i,j,tot=0; char ss[2]; // setIO("input"); scanf("%s%d%d",ss,&n,&K); for(i=1;i<n;++i) { int a,b,c; scanf("%d%d%d",&a,&b,&c),add(a,b,c),add(b,a,c),tot+=c; } tree::dfs1(1,0); tree::dfs2(1,1); mx[0]=sn=n,root=0,getroot(1,0),prepare(root); for(i=1;i<=n;++i) { int l=1,r=tot,mid,ans=0; while(l<=r) { mid=(l+r)>>1; if(query(i,mid)>=K) { ans=mid,r=mid-1; } else l=mid+1; } printf("%d\n",ans); } return 0; }