bzoj2117 [ 2010国家集训队 ] -- 点分树+二分答案

考虑点分树。

求出每个重心所管辖的范围内的每个点到它的距离,建成点分树。

查询时二分答案,然后问题就转化为求到x的距离<=d的点的个数。

在点分树上暴力往上跑就行了,注意去重。

时间复杂度:O(nlog3n)

代码:

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<iostream>
  4 #include<algorithm>
  5 #include<vector>
  6 #include<map>
  7 using namespace std;
  8 inline char nc(){
  9     static char buf[100000],*p1=buf,*p2=buf;
 10     if(p1==p2){
 11         p2=(p1=buf)+fread(buf,1,100000,stdin);
 12         if(p1==p2)return EOF;
 13     }
 14     return *p1++;
 15 }
 16 inline void Read(int& x){
 17     char c=nc();
 18     for(;c<‘0‘||c>‘9‘;c=nc());
 19     for(x=0;c>=‘0‘&&c<=‘9‘;x=(x<<3)+(x<<1)+c-48,c=nc());
 20 }
 21 int Len;
 22 char S[30];
 23 inline void Print(int x){
 24     if(x==0)putchar(48);
 25     for(Len=0;x;x/=10)S[++Len]=x%10;
 26     for(;Len;)putchar(S[Len--]+48);putchar(‘\n‘);
 27 }
 28 #define N 100010
 29 vector<int>g[N],g1[N],g2[N];
 30 map<int,int>Dist[N];
 31 struct Edge{
 32     int t,nx,w;
 33 }e[N<<1];
 34 int Num,i,j,k,n,m,x,y,h[N],f[N],Top[N],Son[N],s[N],d[N],D[N],Sum,F[N],p[N],Rt,z,l;
 35 bool b[N];
 36 inline int _Max(int x,int y){return x<y?y:x;}
 37 inline void Add(int x,int y,int z){
 38     e[++Num].t=y;e[Num].w=z;e[Num].nx=h[x];h[x]=Num;
 39 }
 40 inline void Dfs1(int x,int F){
 41     f[x]=F;d[x]=d[F]+1;s[x]=1;
 42     for(int i=h[x];i;i=e[i].nx)
 43     if(e[i].t!=F){
 44         D[e[i].t]=D[x]+e[i].w;
 45         Dfs1(e[i].t,x);
 46         s[x]+=s[e[i].t];
 47         if(s[e[i].t]>s[Son[x]])Son[x]=e[i].t;
 48     }
 49 }
 50 inline void Dfs2(int x,int tp){
 51     Top[x]=tp;
 52     if(Son[x])Dfs2(Son[x],tp);
 53     for(int i=h[x];i;i=e[i].nx)
 54     if(e[i].t!=f[x]&&e[i].t!=Son[x])Dfs2(e[i].t,e[i].t);
 55 }
 56 inline void Get_root(int x,int Fa){
 57     F[x]=0;s[x]=1;
 58     for(int i=h[x];i;i=e[i].nx)
 59     if(e[i].t!=Fa&&!b[e[i].t]){
 60         Get_root(e[i].t,x);
 61         s[x]+=s[e[i].t];
 62         F[x]=_Max(F[x],s[e[i].t]);
 63     }
 64     F[x]=_Max(F[x],Sum-s[x]);
 65     if(F[x]<F[Rt])Rt=x;
 66 }
 67 inline void Dfs3(int l,int x,int F,int y){
 68     for(int i=h[x];i;i=e[i].nx)
 69     if(!b[e[i].t]&&e[i].t!=F)Dfs3(l,e[i].t,x,y+e[i].w);
 70 }
 71 inline int Lca(int x,int y){
 72     while(Top[x]!=Top[y])
 73     if(d[Top[x]]>d[Top[y]])x=f[Top[x]];else y=f[Top[y]];
 74     return d[x]<d[y]?x:y;
 75 }
 76 inline int Get_dist(int x,int y){
 77     int L=Lca(x,y);
 78     return D[x]+D[y]-(D[L]<<1);
 79 }
 80 inline void Solve(int x){
 81     b[x]=1;Dfs3(x,x,0,0);
 82     for(int i=h[x];i;i=e[i].nx)
 83     if(!b[e[i].t]){
 84         Sum=s[x];F[Rt=0]=Sum;Get_root(e[i].t,0);
 85         p[Rt]=x;Solve(Rt);
 86     }
 87 }
 88 inline int Find1(int x,int y){
 89     int l=0,r=g1[x].size()-1,Mid;
 90     while(l<=r){
 91         Mid=l+r>>1;
 92         if(g1[x][Mid]>y)r=Mid-1;else l=Mid+1;
 93     }
 94     return r+1;
 95 }
 96 inline int Find2(int x,int y){
 97     int l=0,r=g2[x].size()-1,Mid;
 98     while(l<=r){
 99         Mid=l+r>>1;
100         if(g2[x][Mid]>y)r=Mid-1;else l=Mid+1;
101     }
102     return r+1;
103 }
104 inline int Calc(int x,int y){
105     int Ans=0,X=x,l=x;
106     for(;x;x=p[x]){
107         Ans+=Find1(x,y-Dist[X][x]);
108         if(x!=X)Ans-=Find2(l,y-Dist[X][x]);
109         l=x;
110     }
111     return Ans;
112 }
113 inline int Work(int x){
114     int l=0,r=n*10000,Mid,Ans;
115     while(l<=r){
116         Mid=l+r>>1;
117         if(Calc(x,Mid)-1<k)l=Mid+1;else Ans=Mid,r=Mid-1;
118     }
119     return Ans;
120 }
121 int main()
122 {
123     Read(n);Read(k);
124     for(i=1;i<n;i++)Read(x),Read(y),Read(z),Add(x,y,z),Add(y,x,z);
125     Dfs1(1,0);Dfs2(1,1);
126     Sum=n;F[Rt=0]=Sum;Get_root(1,0);Solve(Rt);
127     for(i=1;i<=n;i++)
128     for(j=p[i];j;j=p[j])
129     Dist[i][j]=Get_dist(i,j);
130     for(i=1;i<=n;i++)
131     for(j=l=i;j;j=p[j]){
132         g1[j].push_back(Dist[i][j]);
133         if(j!=i)g2[l].push_back(Dist[i][j]);
134         l=j;
135     }
136     for(i=1;i<=n;i++)sort(g1[i].begin(),g1[i].end()),sort(g2[i].begin(),g2[i].end());
137     for(i=1;i<=n;i++)Print(Work(i));
138     return 0;
139 }

bzoj2117

时间: 2024-08-19 13:24:34

bzoj2117 [ 2010国家集训队 ] -- 点分树+二分答案的相关文章

[bzoj2117] [2010国家集训队]Crash的旅游计划

静态信息的点分治. 老套路,对各个重心用数据结构维护所管辖的点到它的距离..再去重一波 查询的时候就直接二分了..如果数据结构用动态开点的线段树的话就可以直接在线段树上找了..不过我还是写了treap 时间复杂度O(nlog^3n) 1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<cstdlib> 5 using namespace std; 6 const int

【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近的距离. 我们二分答案,设当前二分到

[luogu]P1800 software_NOI导刊2010提高(06)[DP][二分答案]

[luogu]P1800 software_NOI导刊2010提高(06) 题目描述 一个软件开发公司同时要开发两个软件,并且要同时交付给用户,现在公司为了尽快完成这一任务,将每个软件划分成m个模块,由公司里的技术人员分工完成,每个技术人员完成同一软件的不同模块的所用的天数是相同的,并且是已知的,但完成不同软件的一个模块的时间是不同的,每个技术人员在同一时刻只能做一个模块,一个模块只能由一个人独立完成而不能由多人协同完成.一个技术人员在整个开发期内完成一个模块以后可以接着做任一软件的任一模块.写

HDU - 6621 K-th Closest Distance 主席树+二分答案

K-th Closest Distance 主席树第二波~ 题意 给你\(n\)个数\(m\)个询问,问\(i\in [l,r]\)计算每一个\(|a_{i}-p|\)求出第\(k\)小 题目要求强制在线\(l = l \oplus ans.r = r \oplus ans.p = p \oplus ans.k = k \oplus ans\)(ans为上次询问的答案) 思路 二分答案\(ans\),找区间\(i\in[l,r], a_{i} \in [p-ans, p+ans]\)里的数量\(

bzoj[2402] 陶陶的难题II 树链剖分+线段树+二分答案+凸包

将y+q/x+p的值设为x 由于i,j互不干扰,所以我们可以将x,y p,q拉出来分别计算 问题转化为存在x,y,满足y-mid*x+q-mid*p>=0的情况下mid最大 不难发现答案具有单调性,于是二分答案 显然要取出一对(x,y)或(p,q)使y(q)-x(p)*mid尽可能大 以x,y举例,若取点1比取点2更优(x1>x2),则(y1-y2)/(x1-x2)>=mid 用单调栈维护上凸包,存到线段树中 查询时二分凸包 写麻烦了... 1 #include<cstdio>

[BZOJ 2141][国家集训队 2011]排队 树状数组套平衡树

这道题也就是一个动态逆序对嘛,本质上就是个查询区间排名 刚刚打了一道 [CQOI 2011]动态逆序对  用的线段树套平衡树,代码如下: #include<iostream> #include<cstdio> #include<cstring> using namespace std; #define pos(i,a,b) for(int i=(a);i<=(b);i++) #define N 101000 #include<cstdlib> #def

P1505 [国家集训队]旅游【树链剖分】

题目描述 Ray 乐忠于旅游,这次他来到了T 城.T 城是一个水上城市,一共有 N 个景点,有些景点之间会用一座桥连接.为了方便游客到达每个景点但又为了节约成本,T 城的任意两个景点之间有且只有一条路径.换句话说, T 城中只有N ? 1 座桥. Ray 发现,有些桥上可以看到美丽的景色,让人心情愉悦,但有些桥狭窄泥泞,令人烦躁.于是,他给每座桥定义一个愉悦度w,也就是说,Ray 经过这座桥会增加w 的愉悦度,这或许是正的也可能是负的.有时,Ray 看待同一座桥的心情也会发生改变. 现在,Ray

P1800 software_NOI导刊2010提高(06)(二分答案)

P1800 software_NOI导刊2010提高(06) 题目描述 一个软件开发公司同时要开发两个软件,并且要同时交付给用户,现在公司为了尽快完成这一任务,将每个软件划分成m个模块,由公司里的技术人员分工完成,每个技术人员完成同一软件的不同模块的所用的天数是相同的,并且是已知的,但完成不同软件的一个模块的时间是不同的,每个技术人员在同一时刻只能做一个模块,一个模块只能由一个人独立完成而不能由多人协同完成.一个技术人员在整个开发期内完成一个模块以后可以接着做任一软件的任一模块.写一个程序,求出

[国家集训队2010]小Z的袜子

★★★   输入文件:hose.in   输出文件:hose.out   简单对比 时间限制:1 s   内存限制:512 MB [题目描述] 作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿.终于有一天,小Z再也无法忍受这恼人的找袜子过程,于是他决定听天由命…… 具体来说,小Z把这N只袜子从1到N编号,然后从编号L到R(L 尽管小Z并不在意两只袜子是不是完整的一双,甚至不在意两只袜子是否一左一右,他却很在意袜子的颜色,毕竟穿两只不同色的袜子会很尴尬. 你的任务便