luoguU60884 【模板】动态点分治套线段树
题目连接:https://www.luogu.org/problemnew/show/U60884
题意:有N个点,标号为1∼N,用N−1条双向带权通道连接,保证任意两个点能互相到达。
Q次询问,问从编号为x的点到达标号L∼R的点其中一个点的最小距离是多少。
说明 :N,Q<1e5,边权<1e4;
思路:不难想到点分树,保存每个点到其“负责”的点的距离,这样的话可以套线段树,线段树保存其他点到点的距离。
但是,点分树上有个需要解决的问题是:如果x顺着点分树向父亲走,那么在父亲保存的线段树中要除去从儿子上来的那一部分(否则的话,不是简单路径,求出来的可能会错)。 想了一下这里很难实现,因为是取min操作,所以线段树上二分估计也不行。 所以卡住了。
然后求问群友,群友提到了虚树,我觉得此题的数据需要没法实现。 后面猛地想通,我们不需要考虑“回走”这种情况,因为我们求的是最小距离,而非简单路径肯定是没有简单路径优的。 那么就是果然如标题所说,是个板子题了。
代码实现:点分树+线段树+树剖求LCA。
点分树:点分治的过程中新建的树,树根是第一次找到是重心,每一层的重心与上一层的重心连边得到点分树。
点分树里保存的是自己作为重心时,会“负责”的点,即此时还没有vis过的,且与自己连通的点。
所有经过“x”到达的点,保存在了两部分里:一是x在点分树里保存的信息。二是x在点分树的祖先里保存的信息(这一部分保留了x向上传递是信息,所以大部分题要把这里除去,此题由于是取min,可以不考虑)。
求LCA:开始用了ST表,但是感觉空间耗费太大,就改为了树剖,跑起来还挺快。
#include<bits/stdc++.h>
#define rep(i,w,v) for(int i=w;i<=v;i++)
#define FOR() for(int i=Laxt[u];i;i=Next[i])
using namespace std;
#define ll long long
#define RG register
#define maxn 100010
#define maxm 200010
#define inf 1e9
int fa[maxn],n,cnt;
int dep[maxn];bool vis[maxn];
int Laxt[maxn],Next[maxm],To[maxm],Len[maxm];
int siz[maxn],fcy[maxn],hson[maxn],Top[maxn];
void add(int u,int v,int len)
{
Next[++cnt]=Laxt[u]; Laxt[u]=cnt; To[cnt]=v; Len[cnt]=len;
}
void dfs1(int u,int ff)
{
fa[u]=ff; siz[u]=;
dep[u]=dep[ff]+;
FOR(){
int v=To[i];if(v==ff)continue;
fcy[v]=fcy[u]+Len[i];
dfs1(v,u); siz[u]+=siz[v];
if(siz[v]>siz[hson[u]]) hson[u]=v;
}
}
void dfs2(int u,int tp)
{
Top[u]=tp;
if(hson[u])dfs2(hson[u],tp);
FOR()
if(To[i]!=fa[u]&&To[i]!=hson[u])
dfs2(To[i],To[i]);
}
int LCA(int u,int v)
{
while(Top[u]^Top[v]) dep[Top[u]]<dep[Top[v]]?v=fa[Top[v]]:u=fa[Top[u]];
return dep[u]<dep[v]?u:v;
}
int Dis(int u,int v){return fcy[u]+fcy[v]-*fcy[LCA(u,v)];}
int Fa[maxn],Size,root,mx,rt[maxn];
void Getroot(int u,int ff)
{
siz[u]=;int ret=;
FOR(){
int v=To[i];if(v==ff||vis[v])continue;
Getroot(v,u);siz[u]+=siz[v];
ret=max(ret,siz[v]);
}
ret=max(ret,Size-siz[u]);
if(ret<mx) mx=ret,root=u;
}
void DFS(int u,int ff)
{
vis[u]=true;Fa[u]=ff;
FOR(){
int v=To[i];if(vis[v])continue;
mx=Size=siz[v];
Getroot(v,u);
DFS(root,u);
}
}
struct in{ int l,r,mn; }s[maxn<<]; int tot;
void modify(int &Now,int L,int R,int pos,int val)
{
if(!Now){Now=++tot; s[tot].mn=inf;}
s[Now].mn=min(s[Now].mn,val);
if(L==R) return; int Mid=(L+R)>>;
if(pos<=Mid) modify(s[Now].l,L,Mid,pos,val);
else modify(s[Now].r,Mid+,R,pos,val);
}
int query(int Now,int L,int R,int l,int r)
{
if(!Now) return inf;
if(l<=L&&r>=R) return s[Now].mn;
int Mid=(L+R)>>,res=inf;
if(l<=Mid) res=min(res,query(s[Now].l,L,Mid,l,r));
if(r>Mid) res=min(res,query(s[Now].r,Mid+,R,l,r));
return res;
}
void Modify(int x)
{
modify(rt[x],,n,x,);
for(int i=x;Fa[i];i=Fa[i]){
int dis=Dis(x,Fa[i]);
modify(rt[Fa[i]],,n,x,dis);
}
}
int Query(int x,int L,int R)
{
int res=query(rt[x],,n,L,R);
for(int i=x;Fa[i];i=Fa[i])
{
int dis=Dis(x,Fa[i]);
res=min(res,dis+query(rt[Fa[i]],,n,L,R));
}
return res;
}
int main()
{
int Q,u,v,len;
scanf("%d",&n);
rep(i,,n-){
scanf("%d%d%d",&u,&v,&len);
add(u,v,len); add(v,u,len);
}
dfs1(,); dfs2(,);
Size=mx=n;
Getroot(,); DFS(root,);
rep(i,,n) Modify(i);
int ans=,l,r,x;
scanf("%d",&Q);
while(Q--){
scanf("%d%d%d",&l,&r,&x);
printf("%d\n",Query(x,l,r));
}
return ;
}
luoguU60884 【模板】动态点分治套线段树的更多相关文章
- BZOJ4317Atm的树&BZOJ2051A Problem For Fun&BZOJ2117[2010国家集训队]Crash的旅游计划——二分答案+动态点分治(点分树套线段树/点分树+vector)
题目描述 Atm有一段时间在虐qtree的题目,于是,他满脑子都是tree,tree,tree…… 于是,一天晚上他梦到自己被关在了一个有根树中,每条路径都有边权,一个神秘的声音告诉他,每个点到其他的 ...
- [APIO2019] [LOJ 3146] 路灯 (cdq分治或树状数组套线段树)
[APIO2019] [LOJ 3146] 路灯 (cdq分治或树状数组套线段树) 题面 略 分析 首先把一组询问(x,y)看成二维平面上的一个点,我们想办法用数据结构维护这个二维平面(注意根据题意这 ...
- BZOJ.4553.[HEOI2016&TJOI2016]序列(DP 树状数组套线段树/二维线段树(MLE) 动态开点)
题目链接:BZOJ 洛谷 \(O(n^2)\)DP很好写,对于当前的i从之前满足条件的j中选一个最大值,\(dp[i]=d[j]+1\) for(int j=1; j<i; ++j) if(a[ ...
- P3157 [CQOI2011]动态逆序对(树状数组套线段树)
P3157 [CQOI2011]动态逆序对 树状数组套线段树 静态逆序对咋做?树状数组(别管归并QWQ) 然鹅动态的咋做? 我们考虑每次删除一个元素. 减去的就是与这个元素有关的逆序对数,介个可以预处 ...
- [TJOI2017][bzoj4889] 不勤劳的图书管理员 [线段树套线段树]
题面 传送门 思路 考虑两本书的位置交换对答案的贡献: (为了方便描述,用"左边那本"和"右边那本"称呼两本我们要交换的书,"中间那本"是我 ...
- 【BZOJ3295】动态逆序对(线段树,树状数组)
[BZOJ3295]动态逆序对(线段树,树状数组) 题面 Description 对于序列A,它的逆序对数定义为满足iAj的数对(i,j)的个数.给1到n的一个排列,按照某种顺序依次删除m个元素,你的 ...
- 【BZOJ2001】[HNOI2010]城市建设(CDQ分治,线段树分治)
[BZOJ2001][HNOI2010]城市建设(CDQ分治,线段树分治) 题面 BZOJ 洛谷 题解 好神仙啊这题.原来想做一直不会做(然而YCB神仙早就切了),今天来怒写一发. 很明显这个玩意换种 ...
- BZOJ 1901 Zju2112 Dynamic Rankings 树状数组套线段树
题意概述:带修改求区间第k大. 分析: 我们知道不带修改的时候直接上主席树就可以了对吧?两个版本号里面的节点一起走在线段树上二分,复杂度是O((N+M)logN). 然而这里可以修改,主席树显然是凉了 ...
- bzoj3196 二逼平衡树 树状数组套线段树
题目传送门 思路:树状数组套线段树模板题. 什么是树状数组套线段树,普通的树状数组每个点都是一个权值,而这里的树状数组每个点都是一颗权值线段树,我们用前缀差分的方法求得每个区间的各种信息, 其实关键就 ...
随机推荐
- qsort与sort
快排是我们平常敲代码和比赛的时候 经常使用到的方法 qsort是函数库中自带的函数 这是一个标准的快排函数 而sort比qsort更是好用 sort对于不同大小的数组 会使用不 ...
- JS实现文字转语音播放
JS实现文字转语音播放背景实现方式第一种:百度文字转语音开放API第二种:微软TTS语音引擎第三种:SpeechSynthesisUtterance总结背景在做项目的过程中,经常会遇到场景是客户要求播 ...
- Java IO 与 NIO 服务器&客户端通信小栗子
本篇包含了入门小栗子以及一些问题的思考 BIO package com.demo.bio; import java.io.*; import java.net.ServerSocket; import ...
- LInux因为缺失网关出现Name or service not known的解决方法
笔者使用的VMware和CentOS 7.0.在安装完镜像包后,便开始配置静态ip.命令如下 vi /etc/sysconfig/network-scripts/ifcfg-ens33 将BOOTPR ...
- Python基础(七)——文件和异常
1.1 读取整个文件 我们可以创建一个 test.txt 并写入一些内容,使用 Python 读文件操作,读出文本内容. with open(r'E:\test.txt') as file_objec ...
- go switch 和java C#有不同
1 switch 后的语句可以有简单的赋值语句 2 case :后的语句结束后不需要break;默认自动结束 除非以 fallthrough 语句结束,否则分支会自动终止 没有条件的 switch 有 ...
- Windows 上的应用程序在运行期间可以给自己改名(可以做 OTA 自我更新)
原文:Windows 上的应用程序在运行期间可以给自己改名(可以做 OTA 自我更新) 程序如何自己更新自己呢?你可能会想到启动一个新的程序或者脚本来更新自己.然而 Windows 操作系统允许一个应 ...
- java之spring mvc之初始spring mvc
1. mvc : mvc框架是处理 http请求和响应的框架 2. mvc 做的事情有哪些: 将 url 映射到一个java的处理方法上 将表单数据提交到 java 类中 将后台 java 类处理的结 ...
- 两台Windows的 IIS 应用站点 基于NLB + ARR 实现双机热备和负载
IIS负载均衡中我们使用微软的ARR,但提到网站的高可用性,ARR只能做请求入口的消息分发服务,这样如果我们的消息分发服务器给down掉啦,那么做再多的应用服务集群也都枉然. 这里我们主要针对解决这一 ...
- python 2.django的镜像安装与第一次项目创建-运行以及app创建
django的设计模式 Django是一个遵循MVC设计模式的框架,MVC是Model.View.Controller的三个单词的简写.分别代表模型.视图.控制器. 而Django也是是一个MTV的设 ...