题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=5664
题意:有一个有n个点的树(2<=n<=50,000),链(a,b)被称作折链,当且仅当根节点到a的路径上没有b,且b到根节点的路径上没有a。问第k长的折链长度为多少
思路:这题是超哥教会的我,先膜一膜:http://blog.csdn.net/acm_fighting/article/details/52369051
一棵树上的链共有n*(n-1)/2条,全存下来明显会爆内存,因此要选择其他方法,问第k大的很多问题都是用二分解决的,这题也可以,不断二分长度,看树上有几条比该长度大的边,就知道了这个长度是树链中的第几长。可以先用树分治记下比该链大的边的个数,然后减去不是折链的边的个数,不是折链的边的个数用dfs维护一个动态的树状数组就可以计算出。

因为要不断二分,所以事先进行树分治的预处理,这样接下来就是计数的操作了,减少了复杂度。

一个点往上的重心有logn个,所以一个点最多要被计算logn次,因此G数组要开15倍大。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
#define MS(x,y) memset(x,y,sizeof(x))
#define PB push_back
#define lowbit(x) (x&(-x))
typedef long long LL;
const int MAXN=5e4+5;
struct Edge{int v,w,nxt;
}edge[MAXN<<1];
int head[MAXN],edgenum;
void addedge(int u,int v,int w){edge[edgenum].v=v;edge[edgenum].w=w;edge[edgenum].nxt=head[u];head[u]=edgenum++;
}
int n,m,k;
vector<int> G[MAXN*15],que[MAXN];
int cnt1,cnt2,Root;bool used[MAXN];
int siz[MAXN];
int root,w;
void dfsroot(int u,int f,int num){siz[u]=1;int K=0;for(int i=head[u];~i;i=edge[i].nxt){int &v=edge[i].v;if(used[v]||v==f) continue;dfsroot(v,u,num);K=max(K,siz[v]);siz[u]+=siz[v];}K=max(K,num-siz[u]);if(K<w) root=u,w=K;
}
void dfsdist(int u,int f,int w){G[cnt1].PB(w);for(int i=head[u];~i;i=edge[i].nxt){int &v=edge[i].v;if(used[v]||v==f) continue;dfsdist(v,u,w+edge[i].w);}
}
void Cal(int u,int w){++cnt1;dfsdist(u,0,w);sort(G[cnt1].begin(),G[cnt1].end());
}
void Work(int u){Cal(u,0);used[u]=true;for(int i=head[u];~i;i=edge[i].nxt){int &v=edge[i].v;if(used[v]) continue;Cal(v,edge[i].w);w=siz[v];root=0;dfsroot(v,0,siz[v]);que[u].PB(root);Work(root);}
}
void init(){for(int i=1;i<=n*10;++i) G[i].clear();for(int i=1;i<=n;++i) que[i].clear();cnt1=cnt2=0;MS(used,false);root=1;w=n;dfsroot(1,0,n);Root=root;Work(root);
}int tr[MAXN<<1],hsh[MAXN<<1];
LL Ans;
int cnt3;
void add(int x,int v){for(;x<MAXN*2;x+=lowbit(x)) tr[x]+=v;
}
LL query(int x){LL ret=0;for(;x;x-=lowbit(x)) ret+=tr[x];return ret;
}
LL cal(int mid){LL ret=0;++cnt2;int num=G[cnt2].size()-1,r=num;for(int i=0;i<num;++i){r=max(i+1,r);while(r>i+1&&G[cnt2][r-1]+G[cnt2][i]>=mid) --r;if(G[cnt2][r]+G[cnt2][i]<mid) continue;ret+=(num-r+1);}return ret;
}
void work(int u,int mid){Ans+=cal(mid);used[u]=true;int x=0;for(int i=head[u];~i;i=edge[i].nxt){int &v=edge[i].v;if(used[v]) continue;Ans-=cal(mid);work(que[u][x++],mid);}
}
void dfs1(int u,int f,int w,int mid){hsh[++cnt3]=w;hsh[++cnt3]=w-mid;for(int i=head[u];~i;i=edge[i].nxt){int &v=edge[i].v;if(v==f) continue;dfs1(v,u,w+edge[i].w,mid);}
}
void dfs2(int u,int f,int w,int mid){int num1=lower_bound(hsh+1,hsh+cnt3+1,w-mid)-hsh;int num2=lower_bound(hsh+1,hsh+cnt3+1,w)-hsh;Ans-=query(num1);add(num2,1);for(int i=head[u];~i;i=edge[i].nxt){int &v=edge[i].v;if(v==f) continue;dfs2(v,u,w+edge[i].w,mid);}add(num2,-1);
}
bool check(int mid,int k){Ans=0;MS(used,false);cnt2=0;work(Root,mid);MS(tr,0);cnt3=0;dfs1(m,0,0,mid);sort(hsh+1,hsh+cnt3+1);cnt3=unique(hsh+1,hsh+cnt3+1)-hsh-1;dfs2(m,0,0,mid);return Ans>=k;
}int main(){int T;scanf("%d",&T);while(T--){MS(head,-1);edgenum=0;scanf("%d%d%d",&n,&m,&k);int u,v,w,maxw=0;for(int i=1;i<n;++i){scanf("%d%d%d",&u,&v,&w);addedge(u,v,w);addedge(v,u,w);maxw=max(maxw,w);}init();int l=0,r=n*maxw,mid,ans=0;while(l<=r){mid=(l+r)>>1;if(check(mid,k)) l=mid+1,ans=mid;else r=mid-1;}if(ans==0) puts("NO");else printf("%d\n",ans);}
}

HDU 5664 Lady CA and the graph 二分,树分治相关推荐

  1. 牛客多校5 - Graph(字典树+分治求最小生成树)

    题目链接:点击查看 题目大意:给出一棵树,每条边都有一个权值,每次操作可以删除任意一条边或者增加任意权值的一条边,现在可以执行数次操作,不过任何时间都要满足以下两个条件: n 个点互相连通 所有环的权 ...

  2. 【bzoj4009】[HNOI2015]接水果 DFS序+树上倍增+整体二分+树状数组

    题目描述 给出一棵n个点的树,给定m条路径,每条路径有一个权值.q次询问求一个路径包含的所有给定路径中权值第k小的. 输入 第一行三个数 n和P 和Q,表示树的大小和盘子的个数和水果的个数. 接下来n ...

  3. jzoj4050-寻宝游戏【二分,树状数组,LCA】

    正题 题目链接:https://jzoj.net/senior/#contest/show/3017/1 题目大意 nnn个点的一棵树,mmm次操作,修改一个地方的宝藏. 每次操作后求拿完所以宝藏并回 ...

  4. bzoj4418 [Shoi2013]扇形面积并 扫描线+二分+树状数组

    Description 给定N个同心的扇形,求有多少面积,被至少K个扇形所覆盖. 对于100%的数据,1≤n≤105, 1≤m≤106,1≤k≤5000,1≤ri≤105,-m≤a1,a2≤m Sol ...

  5. HDU 4282 A very hard mathematic problem 二分题目

    http://acm.hdu.edu.cn/showproblem.php?pid=4282 题解:http://www.cnblogs.com/E-star/archive/2012/09/11/2 ...

  6. hdu 1054 Strategic Game 最小点覆盖 = 最大二分匹配

    题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=1054 简单二分匹配,根据题意构造一个无向图.然后求最小点覆盖,然后扫描mark数组将曾经匹配的点所匹配 ...

  7. hdu 2141 Can you find it(二分)

    链接:http://acm.hdu.edu.cn/showproblem.php?pid=2141 题意:给出三个数列a,b,c和一组数x,求对于每个x是否存在 ai + bj + ck = x;其中 ...

  8. hdu 4430 Yukari's Birthday (简单数学 + 二分)

    Problem - 4430 题意是,给出蜡烛的数量,要求求出r和k,r是蜡烛的层数,k是每一层蜡烛数目的底数. 开始的时候,没有看清题目,其实中间的那根蜡烛是可放可不放的.假设放置中间的那根蜡烛,就 ...

  9. HDU多校1 - 6756 Finding a MEX(分块+二分+树状数组)

    题目链接:点击查看 题目大意:给出一个 n 个点和 m 条边的无向图,每个点都有一个权值,现在需要执行 q 次操作,每次操作分为两种类型: 1 pos val :将第 pos 个点的权值修改为 val ...

最新文章

  1. 影响数据库性能的因素
  2. 搞怪菜鸟加入域全程图解[为企业部署Windows Server 2008系列十二]
  3. circle后面是什么意思 python_Ape circle Python操作-第2-01章-列表操作,小猿圈,作业
  4. python pip清华源安装库
  5. Xilinx PCIE IP核接口介绍
  6. 6400万像素时代来了,小米首个入局
  7. 十三种寂寞 你有过吗?『最无奈的是第13种』
  8. 恢复触摸板功能的方法
  9. Unity3D资源加载Resources
  10. 普元EOS之性能调优
  11. 视频剪辑-mkv文件导入PR
  12. 手写板(数位板)如何和希沃白板5无缝切换
  13. cesium label和billboard 的一些配置注释
  14. 排队系统拥塞控制的位置
  15. asyncore斗鱼弹幕抓取
  16. GC overhead limit exceeded问题
  17. 机器人运动学标定:基于指数积的串联机构运动学标定
  18. 运动图像目标检测与跟踪简述
  19. css3字体闪烁炫酷,css3 scale动画 字体、输入框等会闪烁,怎么解决?
  20. Python3.9版本发布,不同领域的程序员如何学Python?

热门文章

  1. 7-14 电话聊天狂人 (25分)
  2. 网页抓取及信息提取(三)
  3. 西游记中孙悟空的两位师父
  4. 对接微信二维码支付流程
  5. bzoj-1031 字符加密Cipher
  6. linux安装、更新、卸载anaconda
  7. 什么是大数据,大数据的特点
  8. fedora nginx php,在Fedora 24服务器和工作站上使用MariaDB和PHP / PHP-FPM设置Nginx
  9. HDTV入门扫盲篇HDTV入门
  10. 方舟 linux服务器设置,方舟生存进化私人服务器怎么设置 方舟手游私服设置教程...