xsy1197 树 二分+点分树+二分
Posted xiefengze1
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 }
以上是关于xsy1197 树 二分+点分树+二分的主要内容,如果未能解决你的问题,请参考以下文章