BZOJ 5129: [Lydsy1712月赛]树上传送 点分树+Dijkstra
Description
http://www.lydsy.com/JudgeOnline/upload/201712/prob12.pdf
Input
Output
暑假集训的时候点分树做的比较少,所以做这道题比较吃力,然而现在看这道题就比较简单了.
考虑直接建立点分树,每一个节点只需维护点分子树中 $BFS$ 序.
这样的好处是子树中点的深度是连续的,所以每次能到达的点肯定是连续的区间.
那么,只需按照 $Dijkstra$ 的运行过程,将点加入到优先队列中,并扩展队首.
每次扩展只需边删掉 $BFS$ 序中可以到达的点并加入到堆中,然后一边跳点分树中父亲即可.
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=300005;
namespace IO {
void setIO(string s) {
string in=s+".in";
string out=s+".out";
freopen(in.c_str(),"r",stdin);
freopen(out.c_str(),"w",stdout);
}
char *p1,*p2,buf[100000];
#define nc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)
int rd() {
int x=0;
char c=nc();
while(c<48) c=nc();
while(c>47) x=(((x<<2)+x)<<1)+(c^48),c=nc();
return x;
}
};
namespace tree{
int edges;
int hd[maxn],to[maxn<<1],nex[maxn<<1];
int fa[maxn],top[maxn],siz[maxn],son[maxn],dep[maxn];
void addedge(int u,int v) {
nex[++edges]=hd[u],hd[u]=edges,to[edges]=v;
}
void dfs1(int u,int ff) {
dep[u]=dep[ff]+1,fa[u]=ff,siz[u]=1;
for(int i=hd[u];i;i=nex[i]) {
int v=to[i];
if(v==ff) continue;
dfs1(v,u), siz[u]+=siz[v];
if(siz[v]>siz[son[u]]) son[u]=v;
}
}
void dfs2(int u,int tp) {
top[u]=tp;
if(son[u]) dfs2(son[u],tp);
for(int i=hd[u];i;i=nex[i]) {
int v=to[i];
if(v==fa[u]||v==son[u])continue;
dfs2(v,v);
}
}
int LCA(int x,int y) {
while(top[x]^top[y]) {
dep[top[x]]>dep[top[y]]?x=fa[top[x]]:y=fa[top[y]];
}
return dep[x]<dep[y]?x:y;
}
int Dis(int x,int y) {
return dep[x]+dep[y]-(dep[LCA(x,y)]*2);
}
};
namespace Divide {
struct Node {
int dis,u;
Node(int dis=0,int u=0):dis(dis),u(u){}
}st[maxn],val[maxn*30];
queue<Node>q;
int mn,root,tp,edges;
int siz[maxn],mx[maxn],mark[maxn],Fa[maxn],in[maxn],hd[maxn],to[maxn*30],nex[maxn*30];
void Add(int u,Node e) {
nex[++edges]=hd[u],hd[u]=edges,val[edges]=e;
}
void getroot(int u,int ff) {
mx[u]=0, siz[u]=1;
for(int i=tree::hd[u];i;i=tree::nex[i]) {
int v=tree::to[i];
if(v==ff||mark[v]) continue;
getroot(v,u), siz[u]+=siz[v];
mx[u]=max(mx[u],siz[v]);
}
mx[u]=max(mx[u], mn-siz[u]);
if(mx[u] < mx[root]) root=u;
}
void bfs(int u) {
tp=0;
q.push(Node(0,u));
in[u]=u;
while(!q.empty()) {
Node e=q.front(); q.pop();
st[++tp]=e;
int x=e.u;
for(int i=tree::hd[x];i;i=tree::nex[i]) {
int v=tree::to[i];
if(mark[v]||in[v]==u) continue;
in[v]=u;
q.push(Node(e.dis+1,v));
}
}
for(int i=tp;i>=1;--i) Add(u, st[i]);
}
void divide(int u) {
mark[u]=1;
bfs(u);
for(int i=tree::hd[u];i;i=tree::nex[i]) {
int v=tree::to[i];
if(mark[v]) continue;
root=0,mn=siz[v],getroot(v,u);
Fa[root]=u;
divide(root);
}
}
void pre(int n) {
mx[0]=1000000000,mn=n,root=0,getroot(1,0);
divide(root);
}
};
int n,S;
int L[maxn];
ll C[maxn];
namespace Dijkstra {
ll d[maxn];
int flag[maxn];
struct Node {
ll dis;
int u;
Node(ll dis=0,int u=0):dis(dis),u(u){}
bool operator<(Node b) const {
return dis>b.dis;
}
};
priority_queue<Node>q;
void del(int x,int limit,ll ge,int u) {
if(limit<0) return;
while(Divide::hd[x] && Divide::val[Divide::hd[x]].dis<=limit) {
int v=Divide::val[Divide::hd[x]].u;
Divide::hd[x]=Divide::nex[Divide::hd[x]];
if(flag[v]) continue;
d[v]=ge, flag[v]=1, q.push(Node(d[v] + C[v], v));
}
if(Divide::Fa[x]) del(Divide::Fa[x],L[u]-tree::Dis(u,Divide::Fa[x]),ge,u);
}
void solve() {
d[S]=0,flag[S]=1;
q.push(Node(C[S],S));
while(!q.empty()) {
Node e=q.top(); q.pop();
del(e.u, L[e.u], e.dis, e.u);
}
}
};
int main() {
using namespace IO;
// setIO("input");
n=rd(),S=rd();
for(int i=1;i<n;++i) {
int u=rd(),v=rd();
tree::addedge(u,v);
tree::addedge(v,u);
}
tree::dfs1(1,0);
tree::dfs2(1,1);
for(int i=1;i<=n;++i) L[i]=rd(), C[i]=(ll)rd();
Divide::pre(n);
Dijkstra::solve();
for(int i=1;i<=n;++i) printf("%lld\n",Dijkstra::d[i]);
return 0;
}
BZOJ 5129: [Lydsy1712月赛]树上传送 点分树+Dijkstra的更多相关文章
- bzoj 5125: [Lydsy1712月赛]小Q的书架
新学了一波 决策单调性 dp 套路.... 这种dp一般是长这样的 => f[i][j] = max/min { f[i-1][k] + cost(k+1,j)} ,其中cost函数满足四边形 ...
- bzoj 5123: [Lydsy1712月赛]线段树的匹配
设f[0/1][x]为区间[1,x]的根向下 不选(0)或者选(1) 的dp pair<最优值,方案数>. 可以很容易的发现总状态数就是log级别的,因为2*n 与 (2*n+1 或者 ...
- [BZOJ 5127][Lydsy1712月赛]数据校验
Description 题库链接 给你一个长度为 \(n\) 的序列.\(m\) 次询问,每次询问序列的一个区间 \([l,r]\).对于 \([l,r]\) 内的所有子区间,询问值域是否连续.若存在 ...
- BZOJ 4881: [Lydsy1705月赛]线段游戏 动态规划 + 线段树
Description quailty和tangjz正在玩一个关于线段的游戏.在平面上有n条线段,编号依次为1到n.其中第i条线段的两端点坐 标分别为(0,i)和(1,p_i),其中p_1,p_2,. ...
- BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 )
BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 ) 题意分析 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 ...
- BZOJ Lydsy5月月赛 ADG题解
题目链接 BZOJ5月月赛 题解 好弱啊QAQ只写出三题 A 判断多干个数乘积是否是某个数的倍数有很多方法,比较常用的是取模,但这里并不适用,因为模数不定 会发现数都比较小,所以我们可以考虑分解质因子 ...
- KMP + BZOJ 4974 [Lydsy1708月赛]字符串大师
KMP 重点:失配nxtnxtnxt数组 意义:nxt[i]nxt[i]nxt[i]表示在[0,i−1][0,i-1][0,i−1]内最长相同前后缀的长度 图示: 此时nxt[i]=jnxt[i]=j ...
- BZOJ 3924 / Luogu P3345 [ZJOI2015]幻想乡战略游戏 (动态点分治/点分树)
题意 树的结构不变,每个点有点权,每一条边有边权,有修改点权的操作,设xxx为树中一点.求∑idist(x,i)∗a[i]\sum_idist(x,i)*a[i]i∑dist(x,i)∗a[i]的最 ...
- 【BZOJ 3735】苹果树 树上莫队(树分块+离线莫队+鬼畜的压行)
2016-05-09 UPD:学习了新的DFS序列分块,然后发现这个东西是战术核导弹?反正比下面的树分块不知道要快到哪里去了 #include<cmath> #include<cst ...
随机推荐
- ARTS挑战
最近有点迷茫,感觉自己工作了一年多,技术成长有限,我要做出改变.2019年11月2日,就从今天开始,参加耗子叔的ARTS挑战. ARTS的初衷 Algorithm:主要是为了编程训练和学习.每周至少做 ...
- POJ 1330 Nearest Common Ancestors (dfs+ST在线算法)
详细讲解见:https://blog.csdn.net/liangzhaoyang1/article/details/52549822 zz:https://www.cnblogs.com/kuang ...
- 文件类型 | 命令ln | 软链接硬链接
1.9文件类型 1.9.1常见文件类型 d:目录 -:普通文件 l:链接文件 b:设备 1.9.2文件后缀名 sh:shell脚本 tar.gz:压缩包 my.cnf:配置文件 test.zip:压缩 ...
- 2019CSP-S游记(?)
认识我的人都知道,我懒得写算法和模拟赛的博客,但是游记就不一样了,它比较好玩. Day0 中午随便收拾了下就坐高铁出发了,一个小时左右就到南昌了,随后坐公交,再步行到宾馆安置(也没多远). 宾馆离学校 ...
- [转帖]PostgreSQL ident和peer基于操作系统用户的认证
PostgreSQL ident和peer基于操作系统用户的认证 https://yq.aliyun.com/articles/55898 其实 local和127. 还是有区别的 这里面应该就是对应 ...
- Python内置函数compile
英文文档: compile(source, filename, mode, flags=0, dont_inherit=False, optimize=-1) Compile the source i ...
- CAS单点登录系统--进阶
2.CAS服务端数据源设置 2.1需求分析 我们现在让用户名密码从我们的优乐选的user表里做验证 2.2配置数据源 (1)修改cas服务端中web-inf下deployerConfigContext ...
- ubuntu install xsltproc docbook-xsl docbook-xml
问题一: $ makexsltproc --output phtml/ param.xsl ./pxml/mainbook.xmlmake: xsltproc: Command not foundma ...
- 用R语言提取数据框中日期对应年份(列表转矩阵)
用R语言提取数据框中日期对应年份(列表转矩阵) 在数据处理中常会遇到要对数据框中的时间做聚类处理,如从"%m/%d/%Y"中提取年份. 对应操作为:拆分成列表——列表转矩阵——利用 ...
- 基于TCP/UDP协议的socket
基于TCP协议的socket tcp是基于链接的,必须先启动服务端,然后再启动客户端去链接服务端 server端 import socket sk = socket.socket() sk.bind( ...