【xsy1197】 树 二分+点分树+二分

题目大意:给你一棵n个点的带权树和正整数K,求每个点到其它所有点距离中第K大的数值。

其中,边权10000n50000

我们通过原树构建一棵点分治树,令fa[u]u在点分树上的father

对于每个点u,我们维护两个有序数组fg

其中f[i]表示以u为根的点分树中,距离ui近的距离。(显然里面有siz[u]个数值)

g[i]表示以u为根的点分树中,距离fa[u]第i近的距离。

我们二分答案,设当前二分到的值为p,我们要求所有与u距离p的数量。

然后答案显然为vancestor[u](f[v][i]pdis(v,u)1g[v][i]pdis(fa[v],u)1)

这样单次询问的时间复杂度显然是O(log3n)的。

然后时间复杂度就是O(n log3 n)

完结撒花

复制代码
  1 #include<bits/stdc++.h>
  2 #define M 50005
  3 #define INF 19890604
  4 using namespace std;
  5 
  6 struct edge{int u,v,next;}e[M*2]={0}; int head[M]={0},use=0;
  7 void add(int x,int y,int z){use++;e[use].u=y;e[use].v=z;e[use].next=head[x];head[x]=use;}
  8 int n,k;
  9 int f[M][20]={0},d[M]={0},dep[M]={0};
 10 
 11 void dfs(int x,int fa){
 12     f[x][0]=fa; dep[x]=dep[fa]+1;
 13     for(int i=1;i<20;i++) f[x][i]=f[f[x][i-1]][i-1];
 14     for(int i=head[x];i;i=e[i].next) if(e[i].u!=fa){
 15         d[e[i].u]=d[x]+e[i].v;
 16         dfs(e[i].u,x);
 17     }
 18 }
 19 int getlca(int x,int y){
 20     if(dep[x]<dep[y]) swap(x,y); int cha=dep[x]-dep[y];
 21     for(int i=19;~i;i--) if((1<<i)&cha) x=f[x][i];
 22     for(int i=19;~i;i--) if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
 23     if(x==y) return x; return f[x][0];
 24 }
 25 int getdis(int x,int y){
 26     int lca=getlca(x,y);
 27     return d[x]+d[y]-2*d[lca];
 28 }
 29 
 30 int vis[M]={0},siz[M]={0},minn=INF,minid=0;
 31 void dfssiz(int x,int fa){
 32     siz[x]=1;
 33     for(int i=head[x];i;i=e[i].next)
 34     if(e[i].u!=fa&&vis[e[i].u]==0){
 35         dfssiz(e[i].u,x);
 36         siz[x]+=siz[e[i].u];
 37     }
 38 }
 39 void dfsmin(int x,int fa,int fsiz){
 40     int maxn=fsiz-siz[x];
 41     for(int i=head[x];i;i=e[i].next)
 42     if(e[i].u!=fa&&vis[e[i].u]==0){
 43         dfsmin(e[i].u,x,fsiz);
 44         maxn=max(maxn,siz[e[i].u]);
 45     }
 46     if(maxn<minn) minn=maxn,minid=x;
 47 }
 48 int makeroot(int x){
 49     dfssiz(x,0); 
 50     minn=INF; minid=0;
 51     dfsmin(x,0,siz[x]);
 52     return minid;
 53 }
 54 vector<int> F[M],G[M];
 55 
 56 void addvec(int x,int fa,int X,int FA,int nowdis){
 57     F[X].push_back(getdis(x,X));
 58     G[X].push_back(getdis(x,FA));
 59     for(int i=head[x];i;i=e[i].next)
 60     if(e[i].u!=fa&&vis[e[i].u]==0)
 61     addvec(e[i].u,x,X,FA,nowdis+e[i].v);
 62 }    
 63 int fa[M]={0};
 64 void build(int x,int Fa){
 65     x=makeroot(x); vis[x]=1; fa[x]=Fa;
 66     addvec(x,fa[x],x,fa[x],0);
 67     sort(F[x].begin(),F[x].end());
 68     sort(G[x].begin(),G[x].end());
 69     for(int i=head[x];i;i=e[i].next) if(vis[e[i].u]==0){
 70         build(e[i].u,x);
 71     }
 72 }
 73 
 74 bool check(int x,int mid){
 75     int res=-1,X=x;
 76     for(;x;x=fa[x]){
 77         
 78         res+=upper_bound(F[x].begin(),F[x].end(),mid-getdis(X,x))-F[x].begin();
 79         if(fa[x]) res-=upper_bound(G[x].begin(),G[x].end(),mid-getdis(X,fa[x]))-G[x].begin();
 80     }
 81     return res>=k;
 82 }    
 83 
 84 int main(){
 85     scanf("%d%d",&n,&k);
 86     for(int i=1;i<n;i++){
 87         int x,y,z; scanf("%d%d%d",&x,&y,&z);
 88         add(x,y,z); add(y,x,z);
 89     }
 90     dfs(1,0);  
 91     build(1,0);
 92     for(int i=1;i<=n;i++){
 93         int l=0,r=10000*n;
 94         while(l<r){
 95             int mid=(l+r)>>1;
 96             if(check(i,mid)) r=mid;
 97             else l=mid+1;
 98         }
 99         printf("%d\n",l);
100     }
101 }
复制代码

 

posted @   AlphaInf  阅读(182)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
点击右上角即可分享
微信分享提示