BZOJ4317Atm的树&BZOJ2051A Problem For Fun&BZOJ2117[2010国家集训队]Crash的旅游计划——二分答案+动态点分治(点分树套线段树/点分树+vector)
题目描述
输入
输出
样例输入
1 5 2
1 2 4
2 3 6
2 4 5
样例输出
5
10
9
6
提示
#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)的更多相关文章
- BZOJ2117: [2010国家集训队]Crash的旅游计划
裸点分,点分树每层维护有序表,查询二分,复杂度$O(nlog^3n)$. #include<bits/stdc++.h> #define M (u+v>>1) #define ...
- 【BZOJ2117】 [2010国家集训队]Crash的旅游计划
[BZOJ2117] [2010国家集训队]Crash的旅游计划 Description 眼看着假期就要到了,Crash由于长期切题而感到无聊了,因此他决定利用这个假期和好友陶陶一起出去旅游. Cra ...
- [BZOJ2051]A Problem For Fun/[BZOJ2117]Crash的旅游计划/[BZOJ4317]Atm的树
[BZOJ2051]A Problem For Fun/[BZOJ2117]Crash的旅游计划/[BZOJ4317]Atm的树 题目大意: 给出一个\(n(n\le10^5)\)个结点的树,每条边有 ...
- [BZOJ2117]Crash的旅游计划
Description 眼看着假期就要到了,Crash由于长期切题而感到无聊了,因此他决定利用这个假期和好友陶陶一起出去旅游. Crash和陶陶所要去的城市里有N (N > 1) 个景点,Cra ...
- bzoj3730 震波 [动态点分治,树状数组]
传送门 思路 如果没有强制在线的话可以离线之后CDQ分治随便搞. 有了强制在线之后--可能可以二维线段树?然而我不会算空间. 然后我们莫名其妙地想到了动态点分治,然后这题就差不多做完了. 点分树有一个 ...
- 【BZOJ3110】K大数查询(权值线段树套线段树+标记永久化,整体二分)
题意:有N个位置,M个操作.操作有两种,每次操作 如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c 如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是 ...
- 主席树/线段树模拟归并排序+二分答案(好题)——hdu多校第4场08
用主席树写起来跑的快一点,而且也很傻比,二分答案,即二分那个半径就行 主席树求的是区间<=k的个数 #include<bits/stdc++.h> using namespace s ...
- ZJOI 2017 树状数组(线段树套线段树)
题意 http://uoj.ac/problem/291 思路 不难发现,九条カレン醬所写的树状数组,在查询区间 \([1,r]\) 的时候,其实在查询后缀 \([r,n]\) :在查询 \([l,r ...
- BZOJ4552 HEOI/TJOI2016 排序 线段树、二分答案
题目传送门:https://www.lydsy.com/JudgeOnline/problem.php?id=4552 题意:给出一个$1$到$N$的全排列,对其进行$M$次排序,每次排序将区间$[l ...
随机推荐
- 从CompletableFuture到异步编程设计
从CompletableFuture到异步编程设计,笔者就分为2部分来分享CompletableFuture异步编程设计,前半部分总结下CompletableFuture使用实践,后半部分分享下Com ...
- Go+Python双剑合璧
目的 Python调用Go的方法,Python有很多功能强悍又使用简洁的库.而新生军Go的多核心利用率也是非常强悍的.当然这是明面上的优点.反正你有很多理由想要让Python能够调用Go的方法. 实验 ...
- 旋转数组的最小数字 - 剑指offer 面试题8
题目描述: 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转.输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素.例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋 ...
- UVA 10791 -唯一分解定理的应用
#include<iostream> #include<stdio.h> #include<algorithm> #include<string.h> ...
- Floyd最短路(带路径输出)
摘要(以下内容来自百度) Floyd算法又称为插点法,是一种利用动态规划的思想寻找给定的加权图中多源点之间最短路径的算法,与Dijkstra算法类似. 该算法名称以创始人之一.1978年图灵奖获得者. ...
- mysql 小数转换成百分数查出(保留两位小数百分数)
SELECT id as 'ID',GROUP_CONCAT(concat(truncate(royalties *100,2),'%')) as '比例' FROM yser FROM id in( ...
- python文件、文件夹的移动、复制、删除、重命名
import os.path ,shutil shutil.copytree("G://qqfile","G://new_qqfile")# 第一个是原来的文件 ...
- p201 谱集是闭集 有界集
1 是如何来的? 由1 如何推出 2 2 是如何来的?谢谢 1.σ是的补集 入属于ρ 稠密是因为 T有定义的地方,λI-T都有定义,有界是因为 所以 然后 ρ是σ的补集 模比||T||大的数都 ...
- JQuery/JS select标签动态设置选中值、设置禁止选择 button按钮禁止点击 select获取选中值
//**1.设置选中值:(根据索引确定选中值)**// var osel=document.getElementById("selID"); //得到select的ID var o ...
- React Native之(支持iOS与Android)自定义单选按钮(RadioGroup,RadioButton)
React Native之(支持iOS与Android)自定义单选按钮(RadioGroup,RadioButton) 一,需求与简单介绍 在开发项目时发现RN没有给提供RadioButton和Rad ...