传送门

既然是树上路径统计问题,不难想到要使用树分治,这里以点分治为例

由点分治的性质,每层只需要考虑经过重心的路径

因为需要维护路径长度在一定范围内的最大权值和,所以要用一个数据结构维护一下到根节点距离在一定范围内的最大权值和

显然线段树是一个不错的选择,对每个子树建立一个线段树,根节点的答案用每个子树的线段树都更新一遍即可

考虑更新子树中的点的答案,这时需要使用除这棵子树外的所有子树的线段树一起更新

我们可以使用线段树合并来维护,给子树任意确定一个顺序,然后通过维护每个子树的前缀和后缀线段树的并即可快速得到除去某棵子树后的线段树

显然复杂度是有保证的,因为线段树合并的复杂度无论如何都不会高于暴力插入三遍

总复杂度\(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 树分治+线段树合并的更多相关文章

  1. UVALive 7148 LRIP【树分治+线段树】

    题意就是要求一棵树上的最长不下降序列,同时不下降序列的最小值与最大值不超过D. 做法是树分治+线段树,假设树根是x,y是其当前需要处理的子树,对于子树y,需要处理出两个数组MN,MX,MN[i]表示以 ...

  2. 【BZOJ4372】烁烁的游戏 动态树分治+线段树

    [BZOJ4372]烁烁的游戏 Description 背景:烁烁很喜欢爬树,这吓坏了树上的皮皮鼠.题意:给定一颗n个节点的树,边权均为1,初始树上没有皮皮鼠.烁烁他每次会跳到一个节点u,把周围与他距 ...

  3. LOJ 6145 Easy (动态点分治+线段树)

    题目传送门 先建出来点分树,以每个点为根开线段树,维护点分子树内编号为$[l,r]$的儿子到根的距离最小值 每次查询$x$开始,沿着点分树向上跑,在每个点的线段树的$[l,r]$区间里都查一遍取$mi ...

  4. 【BZOJ3730】震波 动态树分治+线段树

    [BZOJ3730]震波 Description 在一片土地上有N个城市,通过N-1条无向边互相连接,形成一棵树的结构,相邻两个城市的距离为1,其中第i个城市的价值为value[i].不幸的是,这片土 ...

  5. 7.18 NOI模拟赛 因懒无名 线段树分治 线段树维护直径

    LINK:因懒无名 20分显然有\(n\cdot q\)的暴力. 还有20分 每次只询问一种颜色的直径不过带修改. 容易想到利用线段树维护直径就可以解决了. 当然也可以进行线段树分治 每种颜色存一下直 ...

  6. bzoj3730 [震波][动态树分治+线段树+LCA]

    震波 Time Limit: 15 Sec  Memory Limit: 256 MBSubmit: 1573  Solved: 358[Submit][Status][Discuss] Descri ...

  7. LOJ.121.[离线可过]动态图连通性(线段树分治 按秩合并)

    题目链接 以时间为下标建线段树.线段树每个节点开个vector. 对每条边在其出现时间内加入线段树,即,把这条边按时间放在线段树的对应区间上,会影响\(O(\log n)\)个节点. 询问就放在线段树 ...

  8. BZOJ4317Atm的树&BZOJ2051A Problem For Fun&BZOJ2117[2010国家集训队]Crash的旅游计划——二分答案+动态点分治(点分树套线段树/点分树+vector)

    题目描述 Atm有一段时间在虐qtree的题目,于是,他满脑子都是tree,tree,tree…… 于是,一天晚上他梦到自己被关在了一个有根树中,每条路径都有边权,一个神秘的声音告诉他,每个点到其他的 ...

  9. 【loj6145】「2017 山东三轮集训 Day7」Easy 动态点分治+线段树

    题目描述 给你一棵 $n$ 个点的树,边有边权.$m$ 次询问,每次给出 $l$ .$r$ .$x$ ,求 $\text{Min}_{i=l}^r\text{dis}(i,x)$ . $n,m\le ...

随机推荐

  1. C#获取文件版本、文件大小等信息

    使用以下C#程序代码可以非常方便地获取Windows系统中任意一个文件(尤其是可执行文件)的文件版本.文件大小.版权.产品名称等信息.所获取到的信息类似于在Windows操作系统中右键点击该文件,然后 ...

  2. easyui combobox下拉框复制后再禁用,点击不会出现下拉框

    easyui combobox下拉框禁用,点击不会出现下拉框 需要做到,在给easyui combobox赋值后,再禁用easyui combobox 解决办法: $("#time-sele ...

  3. 安卓Android Support Design Library——Snackbar

    介绍: Snackbar是Android Support Design Library库支持的一个控件,用于在界面下面提示一些关键信息,跟Toast不同的地方是SnackBar允许用户向右滑动消除它, ...

  4. 将之前的DotNetOpenAuth项目发布到IIS

    首先需要安装IIS: 控制面板\程序--打开或关闭Windows功能: 默认的不会全选的,需要手动展开选择,能选就全选上吧,特别是asp.net选项,不选的话发布的网站也运行不了. 安装完后需要注册a ...

  5. 忘记mysql密码的解决办法--针对windows系统

    C:\Users\Administrator>cd C:\Program Files\MySQL\MySQL Server 5.5\bin C:\Program Files\MySQL\MySQ ...

  6. RxJava/RxAndroid 使用实例实践

    原文地址 RxAndroid Tutorial响应式编程(Reactive programming)不是一种API,而是一种新的非常有用的范式,而RxJava就是一套基于此思想的框架,在Android ...

  7. java学习-AES加解密之AES-128-CBC算法

    AES算法简介 AES是一种对称加密算法,或称分组对称加密算法.  是Advanced Encryption Standard高级加密标准,简称AES AES的基本要求是,采用对称分组密码体制.分组密 ...

  8. Nodejs学习笔记(十三)—PM2

    简介 PM2 pm2是一个内置负载均衡的node.js应用进程管理器(也支持Windows),其它的类似功能也有不少,但是感觉pm2功能更强,更值的推荐 GitHub地址:https://github ...

  9. PTA (Advanced Level) 1028 List Sorting

    List Sorting Excel can sort records according to any column. Now you are supposed to imitate this fu ...

  10. UOJ #357. 【JOI2017春季合宿】Sparklers

    Description 小S和小M去看花火大会. 一共有 n 个人按顺序排成一排,每个人手上有一个仅能被点燃一次的烟花.最开始时第 K 个人手上的烟花是点燃的. 烟花最多能燃烧 T 时间.每当两个人的 ...