LOJ#6463 AK YOI 树分治+线段树合并
既然是树上路径统计问题,不难想到要使用树分治,这里以点分治为例
由点分治的性质,每层只需要考虑经过重心的路径
因为需要维护路径长度在一定范围内的最大权值和,所以要用一个数据结构维护一下到根节点距离在一定范围内的最大权值和
显然线段树是一个不错的选择,对每个子树建立一个线段树,根节点的答案用每个子树的线段树都更新一遍即可
考虑更新子树中的点的答案,这时需要使用除这棵子树外的所有子树的线段树一起更新
我们可以使用线段树合并来维护,给子树任意确定一个顺序,然后通过维护每个子树的前缀和后缀线段树的并即可快速得到除去某棵子树后的线段树
显然复杂度是有保证的,因为线段树合并的复杂度无论如何都不会高于暴力插入三遍
总复杂度\(O(n\log^2 n)\),常数应该不小,不过跑的挺快233333
#include<bits/stdc++.h>
using namespace std;
const int maxn=100005,maxm=maxn*100;
const long long INF=0x5f5f5f5f5f5f5f5fll;
void solve(int,int);
int getcenter(int,int);
int getdis(int);
void getans(int,int);
void modify(int,int,int&);
int merge(int,int);
long long query(int,int,int);
long long mx[maxm];
int lc[maxm],rc[maxm],cnt=0,root[maxn],prefix[maxn],suffix[maxn];
vector<int>G[maxn];
bool vis[maxn];
long long w[maxn],ans[maxn],ant[maxn],tmp;
int p[maxn],size[maxn],son[maxn],q[maxn],d[maxn],pr[maxn],nx[maxn];
int n,m,L,R,val[maxn],s,t;
int main(){
mx[0]=-INF;
scanf("%d%d%d",&n,&L,&R);
for(int i=1;i<=n;i++){
scanf("%d",&val[i]);
ans[i]=-3472328296227680305ll;
}
for(int i=1,x,y;i<n;i++){
scanf("%d%d",&x,&y);
G[x].push_back(y);
G[y].push_back(x);
}
solve(1,n);
for(int i=1;i<=n;i++){
if(i>1)printf(" ");
printf("%lld",ans[i]);
}
printf("\n");
return 0;
}
void solve(int x,int sz){
x=getcenter(x,sz);
m=sz;
vis[x]=true;
w[x]=val[x];
d[x]=0;
if(sz==1)return;
s=0;
tmp=w[x];
modify(0,m,root[x]);
for(int i=0;i<(int)G[x].size();i++)
if(!vis[G[x][i]]){
p[G[x][i]]=x;
getdis(G[x][i]);
}
s=L;t=R;
for(int i=0,last=0;i<(int)G[x].size();i++)
if(!vis[G[x][i]]){
if(s<=m)ans[x]=max(ans[x],query(0,m,root[G[x][i]]));
prefix[G[x][i]]=merge(prefix[last],root[G[x][i]]);
pr[G[x][i]]=last;
last=G[x][i];
}
ant[x]=-INF;
for(int i=(int)G[x].size()-1,last=0;~i;i--)
if(!vis[G[x][i]]){
suffix[G[x][i]]=merge(suffix[last],root[G[x][i]]);
nx[G[x][i]]=last;
last=G[x][i];
}
for(int i=0;i<(int)G[x].size();i++)
if(!vis[G[x][i]])getans(G[x][i],val[x]);
ans[x]=max(ans[x],ant[x]);
root[x]=0;
for(int i=0;i<(int)G[x].size();i++)
if(!vis[G[x][i]]){
pr[G[x][i]]=nx[G[x][i]]=0;
root[G[x][i]]=prefix[G[x][i]]=suffix[G[x][i]]=0;
}
cnt=0;
for(int i=0;i<(int)G[x].size();i++)
if(!vis[G[x][i]])solve(G[x][i],size[G[x][i]]);
}
int getcenter(int x,int s){
int head=0,tail=0;
q[tail++]=x;
while(head!=tail){
x=q[head++];
size[x]=1;
son[x]=0;
for(int i=0;i<(int)G[x].size();i++)
if(!vis[G[x][i]]&&G[x][i]!=p[x]){
p[G[x][i]]=x;
q[tail++]=G[x][i];
}
}
for(int i=tail-1;i;i--){
x=q[i];
size[p[x]]+=size[x];
if(size[x]>size[son[p[x]]])son[p[x]]=x;
}
x=q[0];
while(son[x]&&size[son[x]]>(s>>1))x=son[x];
return x;
}
int getdis(int x){
int head=0,tail=0,rt=x;
q[tail++]=x;
while(head!=tail){
x=q[head++];
s=d[x]=d[p[x]]+1;
tmp=w[x]=w[p[x]]+val[x];
modify(0,m,root[rt]);
size[x]=1;
for(int i=0;i<(int)G[x].size();i++)
if(!vis[G[x][i]]&&G[x][i]!=p[x]){
p[G[x][i]]=x;
q[tail++]=G[x][i];
}
}
for(int i=tail-1;i;i--){
x=q[i];
size[p[x]]+=size[x];
}
return d[q[tail-1]];
}
void getans(int x,int v){
int head=0,tail=0,rt=merge(prefix[pr[x]],suffix[nx[x]]);
q[tail++]=x;
while(head!=tail){
x=q[head++];
s=L-d[x];
t=R-d[x];
if(t<0||s>m)ant[x]=-INF;
else ant[x]=w[x]-v+query(0,m,rt);
if(s<=0&&t>=0)ant[x]=max(ant[x],w[x]);
for(int i=0;i<(int)G[x].size();i++)
if(!vis[G[x][i]]&&G[x][i]!=p[x]){
p[G[x][i]]=x;
q[tail++]=G[x][i];
}
}
for(int i=tail-1;~i;i--){
x=q[i];
ant[p[x]]=max(ant[p[x]],ant[x]);
ans[x]=max(ans[x],ant[x]);
}
}
void modify(int l,int r,int &rt){
if(!rt){
rt=++cnt;
mx[rt]=-INF;
lc[rt]=rc[rt]=0;
}
mx[rt]=max(mx[rt],tmp);
if(l==r)return;
int mid=(l+r)>>1;
if(s<=mid)modify(l,mid,lc[rt]);
else modify(mid+1,r,rc[rt]);
}
int merge(int x,int y){
if(!x||!y)return x|y;
int z=++cnt;
mx[z]=max(mx[x],mx[y]);
lc[z]=merge(lc[x],lc[y]);
rc[z]=merge(rc[x],rc[y]);
return z;
}
long long query(int l,int r,int rt){
if(s<=l&&t>=r)return mx[rt];
int mid=(l+r)>>1;
if(t<=mid)return query(l,mid,lc[rt]);
if(s>mid)return query(mid+1,r,rc[rt]);
return max(query(l,mid,lc[rt]),query(mid+1,r,rc[rt]));
}
LOJ#6463 AK YOI 树分治+线段树合并的更多相关文章
- UVALive 7148 LRIP【树分治+线段树】
题意就是要求一棵树上的最长不下降序列,同时不下降序列的最小值与最大值不超过D. 做法是树分治+线段树,假设树根是x,y是其当前需要处理的子树,对于子树y,需要处理出两个数组MN,MX,MN[i]表示以 ...
- 【BZOJ4372】烁烁的游戏 动态树分治+线段树
[BZOJ4372]烁烁的游戏 Description 背景:烁烁很喜欢爬树,这吓坏了树上的皮皮鼠.题意:给定一颗n个节点的树,边权均为1,初始树上没有皮皮鼠.烁烁他每次会跳到一个节点u,把周围与他距 ...
- LOJ 6145 Easy (动态点分治+线段树)
题目传送门 先建出来点分树,以每个点为根开线段树,维护点分子树内编号为$[l,r]$的儿子到根的距离最小值 每次查询$x$开始,沿着点分树向上跑,在每个点的线段树的$[l,r]$区间里都查一遍取$mi ...
- 【BZOJ3730】震波 动态树分治+线段树
[BZOJ3730]震波 Description 在一片土地上有N个城市,通过N-1条无向边互相连接,形成一棵树的结构,相邻两个城市的距离为1,其中第i个城市的价值为value[i].不幸的是,这片土 ...
- 7.18 NOI模拟赛 因懒无名 线段树分治 线段树维护直径
LINK:因懒无名 20分显然有\(n\cdot q\)的暴力. 还有20分 每次只询问一种颜色的直径不过带修改. 容易想到利用线段树维护直径就可以解决了. 当然也可以进行线段树分治 每种颜色存一下直 ...
- bzoj3730 [震波][动态树分治+线段树+LCA]
震波 Time Limit: 15 Sec Memory Limit: 256 MBSubmit: 1573 Solved: 358[Submit][Status][Discuss] Descri ...
- LOJ.121.[离线可过]动态图连通性(线段树分治 按秩合并)
题目链接 以时间为下标建线段树.线段树每个节点开个vector. 对每条边在其出现时间内加入线段树,即,把这条边按时间放在线段树的对应区间上,会影响\(O(\log n)\)个节点. 询问就放在线段树 ...
- BZOJ4317Atm的树&BZOJ2051A Problem For Fun&BZOJ2117[2010国家集训队]Crash的旅游计划——二分答案+动态点分治(点分树套线段树/点分树+vector)
题目描述 Atm有一段时间在虐qtree的题目,于是,他满脑子都是tree,tree,tree…… 于是,一天晚上他梦到自己被关在了一个有根树中,每条路径都有边权,一个神秘的声音告诉他,每个点到其他的 ...
- 【loj6145】「2017 山东三轮集训 Day7」Easy 动态点分治+线段树
题目描述 给你一棵 $n$ 个点的树,边有边权.$m$ 次询问,每次给出 $l$ .$r$ .$x$ ,求 $\text{Min}_{i=l}^r\text{dis}(i,x)$ . $n,m\le ...
随机推荐
- maven安装以及eclipse配置maven
详细地址: http://jingyan.baidu.com/article/295430f136e8e00c7e0050b9.html 介绍安装maven,配置Maven环境变量,同时在Eclips ...
- function参数
expr_without_variable { Z_LVAL($$.u.constant) = ; zend_do_pass_param(&$, ZEND_SEND_VAL, Z_LVAL($ ...
- docker安装指定版本TAG的镜像
在docker中安装镜像,一般过程是,docker search 软件名称. 本文以tomcat为例,讲解下载指定版本TAG的tomcat. 搜索tomcat镜像 $ sudo docker sear ...
- 【codeforces 24D】损坏的机器人
题目大意:有一只坏了的机器人站在一个n∗m的网格里,初始位置在(x,y).现在每个单位时间内它会随机选左右下三个方向走,如果它随机的方向会走出网格就不会往这个方向走.当然这个机器人也可能原地停留一个单 ...
- swift 3.0 正则表达式查找/替换字符
1.什么是正则表达式 正则表达式,又称正规表示法.常规表示法(英语:Regular Expression,在代码中常简写为regex.regexp或RE),计算机科学的一个概念.正则表达式使用单个字符 ...
- POJ 2242
#include <iostream> #include <cmath> #include <iomanip> using namespace std; #defi ...
- Mime、base64编码
第一部分 在阮一峰老师的博客中,是这样介绍Mime的: MIME的全称是"Multipurpose Internet Mail Extensions",中译为"多用途互联 ...
- markdown编辑器(颜色、大小、字体)
<font face="黑体">我是黑体字</font> <font face="微软雅黑">我是微软雅黑</font ...
- centos6.5 + 7 静态ip配置
2017/09/19日更, centos6.5 可用 DEVICE=eth0 TYPE=Ethernet ONBOOT=yes NM_CONTROLLED=yes BOOTPROTO=static D ...
- C#(Winform)中button的Enable=false和visible的区别
Enable:可用性 visible:可见性(不是visiable哦,没有这个单词) 如果设置了button或其他控件的Enable为false,还是能够看到控件,只是控件是灰色的,而且点不了: 但设 ...