BZOJ 3784: 树上的路径 点分治+二分+set
很容易想出二分这个思路,但是要想办法去掉一个 $log$.
没错,空间换时间.
双指针的部分错了好几次~
Code:
#include <set>
#include <queue>
#include <cstdio>
#include <vector>
#include <algorithm>
#define N 2000003
#define ll long long
#define setIO(s) freopen(s".in","r",stdin) , freopen(s".out","w",stdout)
using namespace std;
ll answer;
priority_queue<int>q;
vector<int>G[N],F[N],go[N];
int edges,n,root,sn,tmp,len,tt,m,flag;
int hd[N],nex[N<<1],to[N<<1],val[N<<1];
int size[N],mx[N],vis[N];
bool cmp(int a,int b)
{
return a>b;
}
void add(int u,int v,int c)
{
nex[++edges]=hd[u],hd[u]=edges,to[edges]=v,val[edges]=c;
}
void getroot(int u,int ff)
{
size[u]=1,mx[u]=0;
for(int i=hd[u];i;i=nex[i])
if(to[i]!=ff&&!vis[to[i]])
getroot(to[i],u),size[u]+=size[to[i]],mx[u]=max(mx[u],size[to[i]]);
mx[u]=max(mx[u],sn-size[u]);
if(mx[u]<mx[root]) root=u;
}
void getdis(int u,int ff,int dep)
{
F[tmp].push_back(dep);
for(int i=hd[u];i;i=nex[i])
if(to[i]!=ff&&!vis[to[i]])
getdis(to[i],u,dep+val[i]);
}
void prepare(int u)
{
vis[u]=1,G[u].push_back(++tmp),getdis(u,0,0);
for(int i=hd[u];i;i=nex[i])
if(!vis[to[i]])
{
G[u].push_back(++tmp),getdis(to[i],u,val[i]);
root=0,sn=size[to[i]],getroot(to[i],u),go[u].push_back(root),prepare(root);
}
}
ll calc(int u,int t)
{
int l=0,r=F[u].size()-1,pre=0;
if(r<=0) return 0;
ll sum=((ll)(r+1)*r)/2;
while(l<r)
{
if(F[u][l]+F[u][r]<t)
{
sum-=(ll)(r-l);
--r;
}
else
{
++l;
}
}
// printf("%lld\n",sum);
return sum;
}
void dfs(int u,int t)
{
int i;
if(!G[u].empty()) answer+=calc(G[u][0],t);
for(i=1;i<(int)G[u].size();++i) answer-=calc(G[u][i],t);
for(i=0;i<(int)go[u].size();++i) dfs(go[u][i],t);
}
ll check(int t)
{
answer=0,dfs(tt,t);
return answer;
}
multiset<int>S;
multiset<int>::iterator it;
// 长度大于 len 即可
void solve(int u)
{
int i,j;
if(!G[u].empty())
{
for(j=0;j<F[G[u][0]].size();++j)
{
if(F[G[u][0]][j]>len) q.push(F[G[u][0]][j]);
}
if(G[u].size()>=2)
{
int t=G[u][1];
for(j=0;j<F[t].size();++j) S.insert(-F[t][j]);
}
}
for(i=2;i<G[u].size();++i)
{
int t=G[u][i];
// F[t] 与 S 结合
it=S.begin();
for(j=0;j<F[t].size()&&(-(*S.begin())+F[t][0])>len;++j)
{
for(it=S.begin();it!=S.end();it++)
{
if(-(*it)+F[t][j]>len)
{
q.push(-(*it)+F[t][j]);
}
else break;
}
}
for(j=0;j<F[t].size();++j)
S.insert(-F[t][j]);
}
S.clear();
for(int i=0;i<go[u].size();++i) solve(go[u][i]);
}
int main()
{
int i,j,tot=0;
// setIO("input");
scanf("%d%d",&n,&m);
for(i=1;i<n;++i)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c),add(a,b,c),add(b,a,c),tot+=c;
}
mx[root=0]=sn=n,getroot(1,0),tt=root,prepare(root);
for(i=1;i<=tmp;++i) sort(F[i].begin(),F[i].end(),cmp);
int l=0,r=tot,mid,ans=0; while(l<=r)
{
mid=(l+r)>>1;
if(check(mid)>=1ll*m) ans=mid,l=mid+1;
else r=mid-1;
}
len=ans,solve(tt);
while(q.size()<m) q.push(len);
while(!q.empty()) printf("%d\n",q.top()), q.pop();
return 0;
}
BZOJ 3784: 树上的路径 点分治+二分+set的更多相关文章
- BZOJ.3784.树上的路径(点分治 贪心 堆)
BZOJ \(Description\) 给定一棵\(n\)个点的带权树,求树上\(\frac{n\times(n-1)}{2}\)条路径中,长度最大的\(m\)条路径的长度. \(n\leq5000 ...
- bzoj 3784: 树上的路径 堆维护第k大
3784: 树上的路径 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 88 Solved: 27[Submit][Status][Discuss] ...
- bzoj 3784: 树上的路径【点分治+st表+堆】
参考:https://www.cnblogs.com/CQzhangyu/p/7071477.html 神奇的点分治序(或者叫点剖?).就是把点分治扫过的点依次放进队列里,然后发现,对于每一棵树摊到序 ...
- BZOJ 3784: 树上的路径
Description 问一棵树上前 \(k\) 大路径的边权. Sol 边分治. 非常感谢数据没有菊花图. 为了写写边分治试试然后就开了这道题. 边分治非常好想,选一条重边,分成两部分,然后分别求最 ...
- 【BZOJ-3784】树上的路径 点分治 + ST + 堆
3784: 树上的路径 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 462 Solved: 153[Submit][Status][Discuss ...
- 【BZOJ3784】树上的路径 点分治序+ST表
[BZOJ3784]树上的路径 Description 给定一个N个结点的树,结点用正整数1..N编号.每条边有一个正整数权值.用d(a,b)表示从结点a到结点b路边上经过边的权值.其中要求a< ...
- BZOJ 1316: 树上的询问( 点分治 + 平衡树 )
直接点分治, 用平衡树(set就行了...)维护. -------------------------------------------------------------------------- ...
- BZOJ 3697: 采药人的路径 [点分治] [我想上化学课]
传送门 题意: 路径有$-1,1$两种权值,求有多少路径满足权值和为$0$且有一个点将路径分成权值和为$0$的两段 第四节课本来想去上化学,然后快上课了这道题还没调出来.....可恶我想上化学 昨天两 ...
- BZOJ 3697: 采药人的路径 点分治
好久不做点分治的题了,正好在联赛之前抓紧复习一下. 先把边权为 $0$ 的置为 $-1$.定义几个状态:$f[dis][0/1],g[dis][0/1]$ 其中 $f$ 代表在当前遍历的子树内的答案. ...
随机推荐
- SKCTF管理系统
一开始是一个简洁风的登录界面 康康注册界面 嗯...也是很简洁风呢. 那让我们来查看元素(fn+f12) 没有什么有flag的迹象呢! 那我们试一下注册一个账号 这时候我们已经有解题的线索了: 获得管 ...
- Ruby Rails正式学习:Ruby on Rails 做个演示项目吧,逐渐完善
项目开始 一. 新建Rails项目 1. 修改一下Gemfile文件(简单修改一下) source 'https://rubygems.org' git_source(:github) { |repo ...
- VMware中centos7访问外网配置
1.配置虚拟机网络适配器,选择NAT模式 2.在编辑->虚拟机网络编辑器->更改设置 选择目前使用的网卡 3.通过ifconfig查看网卡配置 4.编辑网络配置对应上面网卡名称ens33 ...
- ASP.NET配置KindEditor文本编辑器
文本编辑器:CKEditor和CKFinder KindEditor 1.KindEditor KindEditor 是一套开源的在线HTML编辑器,主要用于让用户在网站上获得所见即所得编辑效果,开 ...
- Linux(16):Shell编程(3)
vim 编程环境配置: .vimrc 文件配置如下:(.vimrc文件放到家目录下:/root :然后退出 xshell 再登陆进来xshell) set nocompatible set histo ...
- Java基础(那些习以为常缺不知道原理的地方)
一.基础 1.1 正确的使用equals方法 Object的equals方法容易抛空指针异常,应使用常量或确定有值的对象来调用 equals.如下代码 // 不能使用一个值为null的引用类型变量来调 ...
- Hadoop大数据平台入门——HDFS和MapReduce
随着硬件水平的不断提高,需要处理数据的大小也越来越大.大家都知道,现在大数据有多火爆,都认为21世纪是大数据的世纪.当然我也想打上时代的便车.所以今天来学习一下大数据存储和处理. 随着数据的不断变大, ...
- Vue 路由(对路由页面编写做规范)
前言 上一篇写了“Vue 路由拦截(对某些页面需要登陆才能访问)” 的博客,此篇是续上篇对路由页面模块化,可以看到之前的路由配置都写在main.js中,真正开发肯定不能都写在main.js,所以我们要 ...
- 写两个线程,一个线程打印1-52,另一个线程打印A-Z,打印顺序为12A34B56C......5152Z
题目: 写两个线程,一个线程打印1-52,另一个线程打印A-Z,打印顺序为12A34B56C......5152Z.要求用线程间的通信. /** * 写两个线程,第一个线程打印1-52,第二个线程打印 ...
- mock.js 模拟数据
1. 劫持请求,返回模拟数据: 用于前后台对接前数据模拟 相比于静态json文件而言:代码完成后不必修改源文件对应的接口调用.可模拟增删改查 2.实例代码 <!doctype html> ...