zoukankan      html  css  js  c++  java
  • 【xsy1197】 树 二分+点分树+二分

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

    其中,边权$≤10000$,$n≤50000$。

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

    对于每个点$u$,我们维护两个有序数组$f$和$g$。

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

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

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

    然后答案显然为$sum_{v∈ancestor[u]} (sum_{f[v][i]≤p-dis(v,u)}1-sum_{g[v][i]≤p-dis(fa[v],u)}1)$

    这样单次询问的时间复杂度显然是$O(log^3n)$的。

    然后时间复杂度就是$O(n log^3 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
    ",l);
    100     }
    101 }
  • 相关阅读:
    图像通道的分离与合并
    frame表单嵌套的定位
    windows10(家庭版)+ laradock 安装踩坑记一记
    Laradock + tp5 + nginx 配置虚拟机域名始终跳转首页/502报错
    php私有组件以及创建自己的composer私有组件(packagist+git+composer)
    申请一个美国paypal账户
    php执行shell脚本
    Linux修复日志
    php7 安装redis拓展
    vim编辑器-删除命令
  • 原文地址:https://www.cnblogs.com/xiefengze1/p/9800854.html
Copyright © 2011-2022 走看看