[Luogu P4178]Tree (点分治+splay)
题面
传送门:https://www.luogu.org/problemnew/show/P4178
Solution
首先,长成这样的题目一定是淀粉质跑不掉了。
考虑到我们不知道K的大小,我们可以开一个splay来统计比某个数小的数的数量。
具体做法等我开淀粉质讲解的坑再满满填(咕)
Code
#include<iostream>
#include<vector>
#include<cstdio>
using namespace std;
long long read()
{
long long x=0,f=1; char c=getchar();
while(!isdigit(c)){if(c=='-') f=-1;c=getchar();}
while(isdigit(c)){x=x*10+c-'0';c=getchar();}
return x*f;
}
const int N=40000+100;
struct road
{
long long w;
int to;
road(int A,long long B)
{
to=A,w=B;
}
};
struct SBT
{
#define root son[0][1]
int fa[N],son[N][2],w[N],size[N],cnt[N],to;
inline void update(int now)
{
size[now]=size[son[now][0]]+size[son[now][1]]+cnt[now];
}
inline void rotate(int x,int type)
{
int y=fa[x],z=fa[y];
fa[x]=z,son[z][y==son[z][1]]=x;
son[y][!type]=son[x][type],fa[son[x][type]]=y;
son[x][type]=y,fa[y]=x;
update(y),update(x);
}
void splay(int now,int to)
{
while(fa[now]!=to)
{
if(now==son[fa[now]][fa[now]==son[fa[fa[now]]][1]] and fa[fa[now]]!=to)
rotate(fa[now],now==son[fa[now]][0]),
rotate(now,now==son[fa[now]][0]);
else
rotate(now,now==son[fa[now]][0]);
}
}
inline void InitTree()
{
root=to=0;
}
inline void init(int now)
{
fa[now]=son[now][0]=son[now][1]=size[now]=w[now]=0;
}
void Insert(int num)
{
if(root==0)
{
root=++to;
init(root);
fa[root]=0;
w[root]=num,cnt[root]=1,update(root);
return;
}
int now=root,last=root;
while(now!=0)
{
if(w[now]==num)
{
cnt[now]++;
splay(now,0);
return;
}
last=now,now=son[now][num>w[now]];
}
now=++to,init(now);
w[now]=num,cnt[now]=1;
fa[now]=last,son[last][num>w[last]]=now;
update(now),splay(now,0);
}
int Query(int num)
{
int now=root,t_ans=0;
while(now!=0)
{
if(num>=w[now])
{
if(w[now]>=w[t_ans]) t_ans=now;
now=son[now][1];
}
else
now=son[now][0];
}
if(t_ans==0) return 0;
splay(t_ans,0);
return size[son[root][0]]+cnt[root];
}
#undef root
}sbt;
vector <road> e[N];
long long n,K;
bool vis[N],t_vis[N],done[N];
int size[N],cnt,root;
int GetSize(int now)
{
t_vis[now]=true;
size[now]=1;
for(int i=0;i<int(e[now].size());i++)
if(t_vis[e[now][i].to]==false and vis[e[now][i].to]==false)
size[now]+=GetSize(e[now][i].to);
t_vis[now]=0;
return size[now];
}
void GetRoot(int now)
{
t_vis[now]=true,size[now]=1;
bool OK=true;
for(int i=0;i<int(e[now].size());i++)
if(t_vis[e[now][i].to]==false and vis[e[now][i].to]==false)
{
GetRoot(e[now][i].to);
size[now]+=size[e[now][i].to];
if(size[e[now][i].to]>cnt/2)
OK=false;
}
if(cnt-size[now]>cnt/2) OK=false;
if(OK==true) root=now;
t_vis[now]=0;
}
int ans;
void dfs2(int now,long long dis,int type)
{
t_vis[now]=true;
if(type==1 and K-dis>=0)
ans+=sbt.Query(K-dis);
else if(type==2)
sbt.Insert(dis);
for(int i=0;i<int(e[now].size());i++)
if(t_vis[e[now][i].to]==false and done[e[now][i].to]==true)
dfs2(e[now][i].to,dis+e[now][i].w,type);
t_vis[now]=false;
}
void dfs(int now)
{
//cerr<<now<<endl;
vis[now]=true;
vector <road> son;
for(int i=0;i<int(e[now].size());i++)
if(vis[e[now][i].to]==false)
{
cnt=GetSize(e[now][i].to);
GetRoot(e[now][i].to);
son.push_back(e[now][i]);
dfs(root);
}
sbt.InitTree();
sbt.Insert(0);
for(int i=0;i<int(son.size());i++)
dfs2(son[i].to,son[i].w,1),dfs2(son[i].to,son[i].w,2);
done[now]=true;
}
int main()
{
freopen("4178.in","r",stdin); n=read();
for(int i=1;i<=n;i++)
e[i].reserve(4);
for(int i=1;i<n;i++)
{
long long s=read(),t=read(),w=read();
e[s].push_back(road(t,w));
e[t].push_back(road(s,w));
}
K=read(); cnt=GetSize(1);
GetRoot(1);
dfs(root); printf("%d",ans);
return 0;
}
[Luogu P4178]Tree (点分治+splay)的更多相关文章
- luogu P4178 Tree
题目链接 luogu P4178 Tree 题解 点分治 代码 // luogu-judger-enable-o2 #include<cstdio> #include<algorit ...
- [Luogu P4178]Tree 题解(点分治+平衡树)
题目大意 给定一棵树,边带权,问有多少点对满足二者间距离$\leq K$,$n \leq 40000$. 题解 点分治专题首杀!$Jackpot!$ (本来看着题意比较简单想捡个软柿子捏,结果手断了… ...
- 洛谷P4178 Tree (点分治)
题目描述 给你一棵TREE,以及这棵树上边的距离.问有多少对点它们两者间的距离小于等于K 输入输出格式 输入格式: N(n<=40000) 接下来n-1行边描述管道,按照题目中写的输入 接下 ...
- 洛谷 P4178 Tree —— 点分治
题目:https://www.luogu.org/problemnew/show/P4178 这道题要把 dep( dis? ) 加入一个 tmp 数组里,排序,计算点对,复杂度很美: 没有写 sor ...
- P4178 Tree 点分治
思路:点分治 提交:1次 题解: 要求权值和\(\leq K\) 的路径,我们可以类比点分治的模板,把长为\(len\)是否存在,改为\(len\)的路径的条数,并用用树状数组维护前缀和,这样就可以求 ...
- [洛谷P4178] Tree (点分治模板)
题目略了吧,就是一棵树上有多少个点对之间的距离 \(\leq k\) \(n \leq 40000\) 算法 首先有一个 \(O(n^2)\) 的做法,枚举每一个点为起点,\(dfs\) 一遍可知其它 ...
- POJ1471 Tree/洛谷P4178 Tree
Tree P4178 Tree 点分治板子. 点分治就是直接找树的重心进行暴力计算,每次树的深度不会超过子树深度的\(\frac{1}{2}\),计算完就消除影响,找下一个重心. 所以伪代码: voi ...
- 【题解】[P4178 Tree]
[题解]P4178 Tree 一道点分治模板好题 不知道是不是我见到的题目太少了,为什么这种题目都是暴力开值域的桶QAQ?? 问点对,考虑点分治吧.直接用值域树状数组开下来,统计的时候直接往树状数组里 ...
- 【Luogu】P2596书架(Splay)
题目链接 通过这题我加深了对Splay的理解,原来Splay的子树也是可以接来接去接到别的点上的,而不是只能旋转qwq 具体接的办法就是swap大法. 对于Top操作我们把当前节点Splay到根,然后 ...
随机推荐
- CentOS7 【linux系统】配置 JDK 教程
1. 下载 [linux版本] JDK 1.8 的包. 2. 导入linux系统里面. 如何导入,下载一个winSCP 软件 破解安装,然后再linux 系统里面 查询IP,连接即可. 在linux解 ...
- Vue.js 学习笔记之三:与服务器的数据交互
显而易见的,之前的02_toDoList存在着一个很致命的缺陷.那就是它的数据只存在于浏览器端,一但用户关闭或重新载入页面,他之前加入到程序中的数据就会全部丢失,一切又恢复到程序的初始状态.要想解决这 ...
- c++模板中set(date st):t(st)中的:符号
转载:https://zhidao.baidu.com/question/618119741512344012.html 半角冒号是构造函数里的初bai始化列表 开始du的标识. 如楼上所述: set ...
- vue使用vueCropper裁剪功能,代码复制直接使用
//先安装包 npm install vue-cropper --save-dev <template> <div id="merchantInformation" ...
- SpringBoot整合Shiro+MD5+Salt+Redis实现认证和动态权限管理|前后端分离(下)----筑基后期
写在前面 在上一篇文章<SpringBoot整合Shiro+MD5+Salt+Redis实现认证和动态权限管理(上)----筑基中期>当中,我们初步实现了SpringBoot整合Shiro ...
- C# 主界面的扁平化
如果需要查看更多文章,请微信搜索公众号 csharp编程大全,需要进C#交流群群请加微信z438679770,备注进群, 我邀请你进群! ! ! --------------------------- ...
- JAVA基础 随机点名器案例
1.1 案例介绍 随机点名器,即在全班同学中随机的找出一名同学,打印这名同学的个人信息. 此案例在我们昨天课程学习中,已经介绍,现在我们要做的是对原有的案例进行升级,使用新的技术来实现. 我 ...
- vs code个性化设置
文件=>首选项=>设置,直接在搜索栏搜索有背景色的部分即可 1. 鼠标滚轮缩放 "editor.mouseWheelZoom": true 2. 显示空格和tab符号 ...
- main函数标准写法
main函数签名 C++中允许两种格式,带参数的和不带参数的: int main() int main(int argc, const char* argv[]) 和C标准不同,C++中main函数必 ...
- 好用的C语言编程软件!工具都没有,怎么用技术改变世界呢!
好用的C语言编程软件 1.VS(Visual Studio) VS(Visual Studio) VS是目前最流行的windows平台应用程序的集成开发环境,由于大部分同学使用的都是Windows ...