题目描述

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

输入

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

输出

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

样例输入

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

样例输出

4
5
10
9
6

提示

100% n<=15000, 边权在1~10之间,为了方便,保证1为根;K<=5000
 
我们先考虑对于单次询问如何用点分治来解决。
对于每个分治中心,如果它处理的联通块中包含查询点,那么需要记录下来联通块中所有点到分治中心的距离+分治中心到查询点的距离,然后容斥去掉与查询点位于分治中心同一棵子树中的点,递归下一层,最后在所有记录的距离中取第k小的。
那么转化到点分树上每个点要记录子树中所有点到这个点的距离及子树中所有点到这个点在点分树上父节点的距离,这个信息在每个点开两棵线段树分别记录一下即可。
因为需要查询多个点的信息并合并,所以不能直接求出第k小,要二分答案然后验证。
BZOJ2117线段树卡内存、平衡树卡时间,但你发现所有查询都在信息添加之后,所以每个点开两个vector然后排序,每次查询在vector上二分查找即可。
时间复杂度O(nlogn^3)。
点分树套线段树

#include<cmath>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
int root[15010];
int froot[15010];
int ls[6000010];
int rs[6000010];
int sum[6000010];
int n,k;
int x,y,z;
int tot;
int num;
int dfn;
int f[15010];
int g[30010][16];
int lg[30010];
int dep[15010];
int val[30010];
int to[30010];
int next[30010];
int head[15010];
int size[15010];
int s[15010];
int rot;
int cnt;
int mx[15010];
int ans;
int vis[15010];
int l,r;
inline void add(int x,int y,int z)
{
tot++;
next[tot]=head[x];
head[x]=tot;
to[tot]=y;
val[tot]=z;
}
inline void dfs(int x,int fa)
{
g[++dfn][0]=dep[x];
s[x]=dfn;
for(int i=head[x];i;i=next[i])
{
if(to[i]!=fa)
{
dep[to[i]]=dep[x]+val[i];
dfs(to[i],x);
g[++dfn][0]=dep[x];
}
}
}
inline void getroot(int x,int fa)
{
size[x]=1;
mx[x]=0;
for(int i=head[x];i;i=next[i])
{
if(!vis[to[i]]&&to[i]!=fa)
{
getroot(to[i],x);
size[x]+=size[to[i]];
mx[x]=max(mx[x],size[to[i]]);
}
}
mx[x]=max(mx[x],num-size[x]);
if(mx[x]<mx[rot])
{
rot=x;
}
}
inline int lca(int x,int y)
{
x=s[x];
y=s[y];
if(x>y)
{
swap(x,y);
}
int len=lg[y-x+1];
return min(g[x][len],g[y-(1<<len)+1][len]);
}
inline int dis(int x,int y)
{
return dep[x]+dep[y]-2*lca(x,y);
}
inline void partation(int x)
{
vis[x]=1;
for(int i=head[x];i;i=next[i])
{
if(!vis[to[i]])
{
num=size[to[i]];
rot=0;
getroot(to[i],0);
f[rot]=x;
partation(rot);
}
}
}
inline void change(int &rt,int l,int r,int k)
{
if(!rt)
{
rt=++cnt;
}
sum[rt]++;
if(l==r)
{
return ;
}
int mid=(l+r)>>1;
if(k<=mid)
{
change(ls[rt],l,mid,k);
}
else
{
change(rs[rt],mid+1,r,k);
}
}
inline int query(int rt,int l,int r,int k)
{
if(!rt||k<0)
{
return 0;
}
if(l==r)
{
return sum[rt];
}
int mid=(l+r)>>1;
if(k<=mid)
{
return query(ls[rt],l,mid,k);
}
else
{
return sum[ls[rt]]+query(rs[rt],mid+1,r,k);
}
}
inline int check(int val,int x)
{
int res=0;
for(int i=x;i;i=f[i])
{
res+=query(root[i],0,150000,val-dis(x,i));
}
for(int i=x;f[i];i=f[i])
{
res-=query(froot[i],0,150000,val-dis(x,f[i]));
}
return res;
}
int main()
{
scanf("%d%d",&n,&k);
k++;
for(int i=1;i<n;i++)
{
scanf("%d%d%d",&x,&y,&z);
add(x,y,z);
add(y,x,z);
}
dfs(1,0);
for(int i=2;i<=dfn;i++)
{
lg[i]=lg[i>>1]+1;
}
for(int j=1;j<=15;j++)
{
for(int i=1;i<=dfn;i++)
{
if(i+(1<<j)-1>dfn)
{
break;
}
g[i][j]=min(g[i][j-1],g[i+(1<<(j-1))][j-1]);
}
}
mx[0]=1<<30;
num=n;
rot=0;
getroot(1,0);
partation(rot);
for(int x=1;x<=n;x++)
{
for(int i=x;i;i=f[i])
{
change(root[i],0,150000,dis(x,i));
}
for(int i=x;f[i];i=f[i])
{
change(froot[i],0,150000,dis(x,f[i]));
}
}
for(int i=1;i<=n;i++)
{
l=0;
r=150000;
ans=-1;
while(l<=r)
{
int mid=(l+r)>>1;
if(check(mid,i)>=k)
{
ans=mid;
r=mid-1;
}
else
{
l=mid+1;
}
}
printf("%d\n",ans);
}
}

点分树+vector

#include<cmath>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
vector<int>sum[100010];
vector<int>fsum[100010];
int n,k;
int x,y,z;
int tot;
int num;
int dfn;
char ch[3];
int f[100010];
int g[200010][17];
int lg[200010];
int dep[100010];
int val[200010];
int to[200010];
int next[200010];
int head[100010];
int size[100010];
int s[100010];
int rot;
int cnt;
int mx[100010];
int ans;
int vis[100010];
int l,r;
int length;
void add(int x,int y,int z)
{
tot++;
next[tot]=head[x];
head[x]=tot;
to[tot]=y;
val[tot]=z;
}
void dfs(int x,int fa)
{
g[++dfn][0]=dep[x];
s[x]=dfn;
for(int i=head[x];i;i=next[i])
{
if(to[i]!=fa)
{
dep[to[i]]=dep[x]+val[i];
dfs(to[i],x);
g[++dfn][0]=dep[x];
}
}
}
void getroot(int x,int fa)
{
size[x]=1;
mx[x]=0;
for(int i=head[x];i;i=next[i])
{
if(!vis[to[i]]&&to[i]!=fa)
{
getroot(to[i],x);
size[x]+=size[to[i]];
mx[x]=max(mx[x],size[to[i]]);
}
}
mx[x]=max(mx[x],num-size[x]);
if(mx[x]<mx[rot])
{
rot=x;
}
}
int lca(int x,int y)
{
x=s[x];
y=s[y];
if(x>y)
{
swap(x,y);
}
int len=lg[y-x+1];
return min(g[x][len],g[y-(1<<len)+1][len]);
}
int dis(int x,int y)
{
return dep[x]+dep[y]-(lca(x,y)<<1);
}
void partation(int x)
{
vis[x]=1;
for(int i=head[x];i;i=next[i])
{
if(!vis[to[i]])
{
num=size[to[i]];
rot=0;
getroot(to[i],0);
f[rot]=x;
partation(rot);
}
}
}
int check(int val,int x)
{
int res=0;
for(int i=x;i;i=f[i])
{
res+=upper_bound(sum[i].begin(),sum[i].end(),val-dis(x,i))-sum[i].begin();
}
for(int i=x;f[i];i=f[i])
{
res-=upper_bound(fsum[i].begin(),fsum[i].end(),val-dis(x,f[i]))-fsum[i].begin();
}
return res;
}
int main()
{
scanf("%s",ch);
scanf("%d%d",&n,&k);
k++;
for(int i=1;i<n;i++)
{
scanf("%d%d%d",&x,&y,&z);
length+=z;
add(x,y,z);
add(y,x,z);
}
dfs(1,0);
for(int i=2;i<=dfn;i++)
{
lg[i]=lg[i>>1]+1;
}
for(int j=1;j<=16;j++)
{
for(int i=1;i<=dfn;i++)
{
if(i+(1<<j)-1>dfn)
{
break;
}
g[i][j]=min(g[i][j-1],g[i+(1<<(j-1))][j-1]);
}
}
mx[0]=1<<30;
num=n;
rot=0;
getroot(1,0);
partation(rot);
for(int x=1;x<=n;x++)
{
for(int i=x;i;i=f[i])
{
sum[i].push_back(dis(i,x));
}
for(int i=x;f[i];i=f[i])
{
fsum[i].push_back(dis(f[i],x));
}
}
for(int i=1;i<=n;i++)
{
sort(sum[i].begin(),sum[i].end());
sort(fsum[i].begin(),fsum[i].end());
}
for(int i=1;i<=n;i++)
{
l=0;
r=length;
ans=-1;
while(l<=r)
{
int mid=(l+r)>>1;
if(check(mid,i)>=k)
{
ans=mid;
r=mid-1;
}
else
{
l=mid+1;
}
}
printf("%d\n",ans);
}
}

BZOJ4317Atm的树&BZOJ2051A Problem For Fun&BZOJ2117[2010国家集训队]Crash的旅游计划——二分答案+动态点分治(点分树套线段树/点分树+vector)的更多相关文章

  1. BZOJ2117: [2010国家集训队]Crash的旅游计划

    裸点分,点分树每层维护有序表,查询二分,复杂度$O(nlog^3n)$. #include<bits/stdc++.h> #define M (u+v>>1) #define ...

  2. 【BZOJ2117】 [2010国家集训队]Crash的旅游计划

    [BZOJ2117] [2010国家集训队]Crash的旅游计划 Description 眼看着假期就要到了,Crash由于长期切题而感到无聊了,因此他决定利用这个假期和好友陶陶一起出去旅游. Cra ...

  3. [BZOJ2051]A Problem For Fun/[BZOJ2117]Crash的旅游计划/[BZOJ4317]Atm的树

    [BZOJ2051]A Problem For Fun/[BZOJ2117]Crash的旅游计划/[BZOJ4317]Atm的树 题目大意: 给出一个\(n(n\le10^5)\)个结点的树,每条边有 ...

  4. [BZOJ2117]Crash的旅游计划

    Description 眼看着假期就要到了,Crash由于长期切题而感到无聊了,因此他决定利用这个假期和好友陶陶一起出去旅游. Crash和陶陶所要去的城市里有N (N > 1) 个景点,Cra ...

  5. bzoj3730 震波 [动态点分治,树状数组]

    传送门 思路 如果没有强制在线的话可以离线之后CDQ分治随便搞. 有了强制在线之后--可能可以二维线段树?然而我不会算空间. 然后我们莫名其妙地想到了动态点分治,然后这题就差不多做完了. 点分树有一个 ...

  6. 【BZOJ3110】K大数查询(权值线段树套线段树+标记永久化,整体二分)

    题意:有N个位置,M个操作.操作有两种,每次操作 如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c 如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是 ...

  7. 主席树/线段树模拟归并排序+二分答案(好题)——hdu多校第4场08

    用主席树写起来跑的快一点,而且也很傻比,二分答案,即二分那个半径就行 主席树求的是区间<=k的个数 #include<bits/stdc++.h> using namespace s ...

  8. ZJOI 2017 树状数组(线段树套线段树)

    题意 http://uoj.ac/problem/291 思路 不难发现,九条カレン醬所写的树状数组,在查询区间 \([1,r]\) 的时候,其实在查询后缀 \([r,n]\) :在查询 \([l,r ...

  9. BZOJ4552 HEOI/TJOI2016 排序 线段树、二分答案

    题目传送门:https://www.lydsy.com/JudgeOnline/problem.php?id=4552 题意:给出一个$1$到$N$的全排列,对其进行$M$次排序,每次排序将区间$[l ...

随机推荐

  1. 立足中国,走向世界(Made in China, Go to World)

    FineUI一路走来已经历经 9 年的风风雨雨,拥有国内最为广泛的捐赠群体(1500多位),和众多企业客户的青睐(200多家). 今天,我们很高兴的宣布:FineUI英文版上线了! FineUI英文版 ...

  2. 《了不起的 nodejs》中 TwitterWeb 案例 bug 解决

    了不起的nodejs算是一本不错的入门书,不过书中个别案例存在bug,按照书中源码无法做出和书中相同效果,原本兴奋的心情掺杂着些许失落. 现在我们看一下第七章HTTP,一个 Twitter Web 客 ...

  3. SpringBoot整合Swagger2搭建API在线文档

    Swagger,中文"拽"的意思,它是一个功能强大的在线API在线文档,目前它的版本为2.x,所以称为Swagger2.Swagger2提供了在线文档的查阅和测试功能.利用Swag ...

  4. 海纳百川而来的一篇相当全面的Java NIO教程

    目录 零.NIO包 一.Java NIO Channel通道 Channel的实现(Channel Implementations) Channel的基础示例(Basic Channel Exampl ...

  5. NO NEWS IS GOOD NEWS

    从客户那传来一个噩耗:要求每个表单在保存之后,要在页面上弹一个 “ 保存成功 ” 的对话框. 客户代表志得意满地说这样用户体验更好,略带谴责意味地傲娇道,“你们早该想到的”.呵呵…… 可不是嘛,我刚入 ...

  6. React组件重构:嵌套+继承 与 高阶组件

    前言 在最近做的一个react项目中,遇到了一个比较典型的需要重构的场景:提取两个组件中共同的部分. 最开始通过使用嵌套组件和继承的方式完成了这次重构. 但是后来又用高阶组件重新写了一遍,发现更好一点 ...

  7. (Beta)Let's-M2后分析报告

    设想和目标 1. 我们的软件要解决什么问题?是否定义得很清楚?是否对典型用户和典型场景有清晰的描述? 在M1阶段我们对用户需求进行了调研,同时M1阶段我们的开发目标就是为了解决用户发起.参与.查看.搜 ...

  8. Mike and strings CodeForces - 798B (又水又坑)

    题目链接 题意:英语很简单,自己取读吧. 思路: 既然n和i字符串的长度都很小,最大才50,那么就是只要能出答案就任意暴力瞎搞. 本人本着暴力瞎搞的初衷,写了又臭又长的200多行(代码框架占了50行) ...

  9. elasticsearch elk最全java api 搜索 聚合、嵌套查询

    目录 一. 一般查询... 2 (一) matchAllQuery(client). 2 (二) matchQuery(client);3 (三) multiMatchQuery(client);3 ...

  10. 使用git将本地项目推送到码云私有仓库

    https://blog.csdn.net/qq_33876553/article/details/80111946 2018年04月27日 19:53:33 桥路丶 阅读数:2958 前言 之前博主 ...