【BZOJ4317】Atm的树

Description

Atm有一段时间在虐qtree的题目,于是,他满脑子都是tree,tree,tree……
于是,一天晚上他梦到自己被关在了一个有根树中,每条路径都有边权,一个神秘的声音告诉他,每个点到其他的点有一个距离(什么是距离不用说吧),他需要对于每个点回答:从这个点出发的第k小距离是多少;
如果atm不能回答出来,那么明天4019的闹钟将不会响,4019全寝可能就迟到了,所以atm希望你帮帮他。

Input

第一行,两个正整数n,k,表示树的点数,询问的是第几小距离;
第二~n行,每行三个正整数x,y,w,表示x和y之间有一条边,x为父亲,边权为w;

Output

n行, 每行一个数,第i行输出从i开始第k小距离

Sample Input

5 2
1 5 2
1 2 4
2 3 6
2 4 5

Sample Output

4
5
10
9
6

HINT

100% n<=15000, 边权在1~10之间,为了方便,保证1为根;K<=5000

题解:依旧是动态点分治。

统计第k大不太好搞,我们对于每个点都二分一下,变成求到一个点距离<=mid的点有多少个,然后就变成熟悉的题了。

我们对于每个点维护一棵线段树,记录它在点分树的子树中有多少个点到它的距离为x,同时为了去重,还要维护一个从它父亲中减去的版本。

时间复杂度$O(nlog_n^3)$。

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int maxn=15010;
int n,m,N,tot,cnt,rt,mn;
int to[maxn<<1],next[maxn<<1],head[maxn],val[maxn<<1],siz[maxn],fa[maxn],md[20][maxn<<1],pos[maxn],vis[maxn];
int Log[maxn<<1],dep[maxn],r1[maxn],r2[maxn];
struct sag
{
int ls,rs,siz;
}s[maxn*100];
inline int rd()
{
int ret=0,f=1; char gc=getchar();
while(gc<'0'||gc>'9') {if(gc=='-') f=-f; gc=getchar();}
while(gc>='0'&&gc<='9') ret=ret*10+gc-'0',gc=getchar();
return ret*f;
}
inline void add(int a,int b,int c)
{
to[cnt]=b,val[cnt]=c,next[cnt]=head[a],head[a]=cnt++;
}
void getrt(int x,int fa)
{
int tmp=0,i;
siz[x]=1;
for(i=head[x];i!=-1;i=next[i]) if(!vis[to[i]]&&to[i]!=fa)
getrt(to[i],x),tmp=max(tmp,siz[to[i]]),siz[x]+=siz[to[i]];
tmp=max(tmp,tot-siz[x]);
if(tmp<mn) mn=tmp,rt=x;
}
void dfs(int x)
{
pos[x]=++pos[0],md[0][pos[0]]=dep[x];
for(int i=head[x];i!=-1;i=next[i]) if(!dep[to[i]]) dep[to[i]]=dep[x]+val[i],dfs(to[i]),md[0][++pos[0]]=dep[x];
}
void solve(int x)
{
vis[x]=1;
for(int i=head[x];i!=-1;i=next[i]) if(!vis[to[i]])
tot=siz[to[i]],mn=1<<30,getrt(to[i],x),fa[rt]=x,solve(rt);
}
inline int dis(int x,int y)
{
int a=pos[x],b=pos[y];
if(a>b) swap(a,b);
int k=Log[b-a+1];
return dep[x]+dep[y]-2*min(md[k][a],md[k][b-(1<<k)+1]);
}
void insert(int l,int r,int &x,int a)
{
if(!x) x=++tot;
s[x].siz++;
if(l==r) return ;
int mid=(l+r)>>1;
if(a<=mid) insert(l,mid,s[x].ls,a);
else insert(mid+1,r,s[x].rs,a);
}
int query(int l,int r,int x,int a,int b)
{
if(a>b) return 0;
if(!x||(a<=l&&r<=b)) return s[x].siz;
int mid=(l+r)>>1;
if(b<=mid) return query(l,mid,s[x].ls,a,b);
if(a>mid) return query(mid+1,r,s[x].rs,a,b);
return query(l,mid,s[x].ls,a,b)+query(mid+1,r,s[x].rs,a,b);
}
inline int calc(int x,int mid)
{
int ret=0,y,z;
for(y=x;y;y=z)
{
z=fa[y];
if(z) ret-=query(0,N,r2[y],0,mid-dis(x,z));
ret+=query(0,N,r1[y],0,mid-dis(x,y));
}
return ret;
}
int main()
{
n=rd(),m=rd()+1;
int i,j,u,v,a,b,c,l,r,mid;
memset(head,-1,sizeof(head));
for(i=1;i<n;i++) a=rd(),b=rd(),c=rd(),add(a,b,c),add(b,a,c),N+=c;
dep[1]=1,dfs(1),tot=n,mn=1<<30,getrt(1,0),solve(rt);
for(i=2;i<(n<<1);i++) Log[i]=Log[i>>1]+1;
for(j=1;(1<<j)<(n<<1);j++) for(i=1;i+(1<<j)-1<(n<<1);i++) md[j][i]=min(md[j-1][i],md[j-1][i+(1<<(j-1))]);
for(i=1;i<=n;i++)
{
for(u=i;u;u=v)
{
v=fa[u];
if(v) insert(0,N,r2[u],dis(i,v));
insert(0,N,r1[u],dis(i,u));
}
}
for(i=1;i<=n;i++)
{
l=0,r=N+1;
while(l<r)
{
mid=(l+r)>>1;
if(calc(i,mid)>=m) r=mid;
else l=mid+1;
}
printf("%d\n",r);
}
return 0;
}

【BZOJ4317】Atm的树 动态树分治+二分+线段树的更多相关文章

  1. luoguU60884 【模板】动态点分治套线段树

    题目连接:https://www.luogu.org/problemnew/show/U60884 题意:有N个点,标号为1∼N,用N−1条双向带权通道连接,保证任意两个点能互相到达. Q次询问,问从 ...

  2. BZOJ4012[HNOI2015]开店——树链剖分+可持久化线段树/动态点分治+vector

    题目描述 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到 人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱.这样的 想法当然非常好啦,但是她们也发现她们面临着一个 ...

  3. 【WC2018】即时战略(动态点分治,替罪羊树)

    [WC2018]即时战略(动态点分治,替罪羊树) 题面 UOJ 题解 其实这题我也不知道应该怎么确定他到底用了啥.只是想法很类似就写上了QwQ. 首先链的部分都告诉你要特殊处理那就没有办法只能特殊处理 ...

  4. 【BZOJ3295】动态逆序对(线段树,树状数组)

    [BZOJ3295]动态逆序对(线段树,树状数组) 题面 Description 对于序列A,它的逆序对数定义为满足iAj的数对(i,j)的个数.给1到n的一个排列,按照某种顺序依次删除m个元素,你的 ...

  5. 【BZOJ2001】[HNOI2010]城市建设(CDQ分治,线段树分治)

    [BZOJ2001][HNOI2010]城市建设(CDQ分治,线段树分治) 题面 BZOJ 洛谷 题解 好神仙啊这题.原来想做一直不会做(然而YCB神仙早就切了),今天来怒写一发. 很明显这个玩意换种 ...

  6. 指针-动态开点&合并线段树

    一个知识点不在一道题里说是没有灵魂的 线段树是用来处理区间信息的咯 但是往往因为需要4倍空间让许多人退却,而动态开点的线段树就非常棒 仿佛只用2倍就可以咯 指针保存位置,即节点信息,是很舒适的,所以用 ...

  7. HDU4614 Vases and Flowers 二分+线段树

    分析:感觉一看就是二分+线段树,没啥好想的,唯一注意,当开始摆花时,注意和最多能放的比大小 #include<iostream> #include<cmath> #includ ...

  8. BZOJ4860 BJOI2017 树的难题 点分治、线段树合并

    传送门 只会线段树……关于单调队列的解法可以去看“重建计划”一题. 看到路径长度$\in [L,R]$考虑点分治.可以知道,在当前分治中心向其他点的路径中,始边(也就是分治中心到对应子树的根的那一条边 ...

  9. J - Joseph and Tests Gym - 102020J (二分+线段树)

    题目链接:https://cn.vjudge.net/contest/283920#problem/J 题目大意:首先给你n个门的高度,然后q次询问,每一次询问包括两种操作,第一种操作是将当前的门的高 ...

随机推荐

  1. ECS 实例网络带宽

    1. 带宽是否独享? 是独享. 2. 带宽单线还是双线,电信还是网通? 多线 BGP(中国电信.联通.移动.教育网等)接入,确保全国用户访问畅通. 3. 5 Mbps 带宽怎么理解? 5 Mbps 带 ...

  2. 给第三方dll加上强命名的方法[C#]

    在VS.NET 的命名行窗口下,输入如下的代码. 1 ,生成一个KeyFile sn -k keyPair.snk 2, 得到程序集的MSIL ildasm SomeAssembly.dll /out ...

  3. 设置SSH编码为中文

    http://www.qzz.in/?post=198下面是详细方法: 方法1: vi /etc/sysconfig/i18n 将内容改为 LANG="zh_CN.GB18030" ...

  4. Linux Load average负载详细解释

    http://tianmaotalk.iteye.com/blog/1027970     Linux Load average负载详细解释   linux查看机器负载

  5. 动态创建 Log4net 实例

    动态创建log4net 实例 根据业务类型,动态的创建日志实例,将日志写到不同目录.常见的配置文件中统一配置,不能满足需求. 引用log4net nuget安装命令: Install-Package ...

  6. 模拟循环单击事件实现layout中间panel全屏

    jquery提供了toggle方法 toggle() 方法切换元素的可见状态. 如果被选元素可见,则隐藏这些元素,如果被选元素隐藏,则显示这些元素. 语法 $(selector).toggle(spe ...

  7. 【转】H.264(H264)视频文件的制作

    转自:http://blog.csdn.net/caoshangpa/article/details/51166109 一.准备工作 1.下载并安装优酷客户端 2.下载ffmpeg可执行文件,解压可用 ...

  8. Linux yum操作无效的解决方法

    1.没网,试着:ping www.baidu.com 如果显示没有连接的话,就说明没网,也就无法使用yum 命令. 2.ping通了的话,还是是用不了yum命令,说明是yum镜像没有了,那么就得下载一 ...

  9. 阅读《Android 从入门到精通》(29)——四大布局

    LinearLayout 类方法 watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQ ...

  10. js 正则表达式 验证小数点后几位

    function IsFloatByBit (value, state, bit) {             if (state == false) {                 var re ...