洛谷 P3714 - [BJOI2017]树的难题(点分治)
咦?鸽子 tzc 竟然来补题解了?incredible(
首先看到这样类似于路径统计的问题我们可以非常自然地想到点分治。每次我们找出每个连通块的重心 \(x\) 然后以 \(x\) 为根 DFS 一遍整个子树,我们假设 \(y\) 到 \(x\) 的距离为 \(dep_y\),\(x\to y\) 这一段上颜色的权值之和为 \(sum_y\),那么考虑怎样合并两条路径。显然对于两个在 \(x\) 不同子树内的点 \(y,z\),\(y\to z\) 路径上边的个数就是 \(dep_y+dep_z\),路径上权值之和就是 \(sum_y+sum_z-c_{col_y}·[col_y=col_z]\),其中 \(col_y\) 为 \(x\to y\) 路径上经过的第一条边的权值。看到这个 \([col_y=col_z]\) 貌似有点棘手,不过注意到我们贡献显然是一个子树一个子树计算的对吧,因此我们考虑将 \(x\) 所有子树按 \(x\) 到这棵子树经过的第一条边的颜色从小到大排序,然后维护两棵线段树,第一棵线段树上下标为 \(d\) 的位置上维护 \(\max\limits_{dep_y=d\land col_y\ne C}sum_y\),第二棵维护 \(\max\limits_{dep_y=d\land col_y=C}sum_y\),其中 \(C\) 为当前颜色种类,然后每次颜色改变就暴力地将第二棵线段树中所有元素插入第一棵线段树中即可,查询就在两棵树中分别查 \([r-dep_y,l-dep_y]\) 的最大值,记作 \(mx1\) 和 \(mx2\),然后用 \(mx1+sum_y,mx2-c_{col_y}+sum_y\) 更新答案即可。
时间复杂度 \(n\log^2n\),其中一个 \(\log\) 在于点分治,一个 \(\log\) 在于线段树。
最后稍微总结一下这类点分治解决树上路径计数题目的解题技巧:首先要考虑怎样合并两段路径,如果不好合并那一般使用点分治不太好解决,其次要思考如何维护两段路径的决策,比较简单的使用一个桶即可维护,比较复杂的需用 BIT/线段树/平衡树解决。对于计数问题,容斥也是一个不错的选择,即先不考虑两个端点不在同一子树这一条件,先一股脑把贡献全加上去,再扣掉在同一子树内的情况。
const int MAXN=2e5;
const int INF=0x3f3f3f3f;
const ll INFll=0x3f3f3f3f3f3f3f3fll;
int n,m,L,R,c[MAXN+5],hd[MAXN+5],to[MAXN*2+5],val[MAXN*2+5],nxt[MAXN*2+5],ec=0;
void adde(int u,int v,int w){to[++ec]=v;val[ec]=w;nxt[ec]=hd[u];hd[u]=ec;}
int mx[MAXN+5],cent=0,siz[MAXN+5];bool vis[MAXN+5];
void findcent(int x,int f,int tot){
mx[x]=0;siz[x]=1;
for(int e=hd[x];e;e=nxt[e]){
int y=to[e];if(y==f||vis[y]) continue;
findcent(y,x,tot);siz[x]+=siz[y];
chkmax(mx[x],siz[y]);
} chkmax(mx[x],tot-siz[x]);
if(mx[cent]>mx[x]) cent=x;
}
int dep[MAXN+5];ll sum[MAXN+5];
void getdep(int x,int f,int pre){
for(int e=hd[x];e;e=nxt[e]){
int y=to[e],z=val[e];if(y==f||vis[y]) continue;
dep[y]=dep[x]+1;sum[y]=sum[x]+((z==pre)?0:c[z]);
getdep(y,x,z);
}
}
struct segtree{
struct node{int l,r;ll mx;} s[MAXN*4+5];
stack<int> stk;
void pushup(int k){s[k].mx=max(s[k<<1].mx,s[k<<1|1].mx);stk.push(k);}
void build(int k,int l,int r){
s[k].l=l;s[k].r=r;s[k].mx=-INFll;if(l==r) return;
int mid=l+r>>1;build(k<<1,l,mid);build(k<<1|1,mid+1,r);
}
void modify(int k,int p,ll v){
if(s[k].l==s[k].r) return chkmax(s[k].mx,v),stk.push(k),void();
int mid=s[k].l+s[k].r>>1;(p<=mid)?modify(k<<1,p,v):modify(k<<1|1,p,v);
pushup(k);
}
ll query(int k,int l,int r){
if(l>r) return -INFll;
if(l<=s[k].l&&s[k].r<=r) return s[k].mx;
int mid=s[k].l+s[k].r>>1;
if(r<=mid) return query(k<<1,l,r);
else if(l>mid) return query(k<<1|1,l,r);
else return max(query(k<<1,l,mid),query(k<<1|1,mid+1,r));
}
void relax(){
while(!stk.empty()){
int k=stk.top();stk.pop();
s[k].mx=-INFll;
}
}
} s1,s2;
vector<int> pt;
ll res=-INFll;
void findpts(int x,int f){
pt.pb(x);
for(int e=hd[x];e;e=nxt[e]){
int y=to[e];if(y==f||vis[y]) continue;
findpts(y,x);
}
}
void divcent(int x){
// printf("divcent %d\n",x);
vis[x]=1;dep[x]=sum[x]=0;
vector<pii> sub;
for(int e=hd[x];e;e=nxt[e]){
int y=to[e],z=val[e];if(vis[y]) continue;
dep[y]=1;sum[y]=c[z];getdep(y,x,z);
sub.pb(mp(z,y));
} sort(sub.begin(),sub.end());
vector<int> wt;s1.modify(1,0,0);
for(int i=0;i<sub.size();i++){
if(i&&sub[i].fi!=sub[i-1].fi){
s2.relax();
for(int y:wt) s1.modify(1,dep[y],sum[y]);
wt.clear();
} int y=sub[i].se;pt.clear();findpts(y,x);
for(int z:pt){
int d=dep[z];
if(d<=R){
chkmax(res,s1.query(1,max(L-d,0),R-d)+sum[z]);
chkmax(res,s2.query(1,max(L-d,0),R-d)+sum[z]-c[sub[i].fi]);
}
} for(int z:pt) wt.pb(z),s2.modify(1,dep[z],sum[z]);
// for(int z:pt) printf("%d %d %lld\n",z,dep[z],sum[z]);
} s1.relax();s2.relax();
for(int e=hd[x];e;e=nxt[e]){
int y=to[e];if(vis[y]) continue;cent=0;
findcent(y,x,siz[y]);divcent(cent);
}
}
int main(){
scanf("%d%d%d%d",&n,&m,&L,&R);s1.build(1,0,n);s2.build(1,0,n);
for(int i=1;i<=m;i++) scanf("%d",&c[i]);
for(int i=1,u,v,w;i<n;i++) scanf("%d%d%d",&u,&v,&w),adde(u,v,w),adde(v,u,w);
mx[0]=INF;findcent(1,0,n);divcent(cent);
printf("%lld\n",res);
return 0;
}
洛谷 P3714 - [BJOI2017]树的难题(点分治)的更多相关文章
- P3714 [BJOI2017]树的难题 点分治+线段树合并
题目描述 题目传送门 分析 路径问题考虑点分治 对于一个分治中心,我们可以很容易地得到从它开始的一条路径的价值和长度 问题就是如何将不同的路径合并 很显然,对于同一个子树中的所有路径,它们起始的颜色是 ...
- [BJOI2017]树的难题 点分治 线段树
题面 [BJOI2017]树的难题 题解 考虑点分治. 对于每个点,将所有边按照颜色排序. 那么只需要考虑如何合并2条链. 有2种情况. 合并路径的接口处2条路径颜色不同 合并路径的接口处2条路径颜色 ...
- [BJOI2017]树的难题 点分治,线段树合并
[BJOI2017]树的难题 LG传送门 点分治+线段树合并. 我不会写单调队列,所以就写了好写的线段树. 考虑对于每一个分治中心,把出边按颜色排序,这样就能把颜色相同的子树放在一起处理.用一棵动态开 ...
- 并不对劲的loj2179:p3714:[BJOI2017]树的难题
题目大意 有一棵树,\(n\)(\(n\leq2*10^5\))个点,每条边\(i\)有颜色\(w_i\),共有\(m\)(\(m\leq n\))种颜色,第\(i\)种颜色的权值是\(c_i\)(\ ...
- BZOJ4860 BJOI2017 树的难题 点分治、线段树合并
传送门 只会线段树……关于单调队列的解法可以去看“重建计划”一题. 看到路径长度$\in [L,R]$考虑点分治.可以知道,在当前分治中心向其他点的路径中,始边(也就是分治中心到对应子树的根的那一条边 ...
- luoguP3714 [BJOI2017]树的难题 点分治
以后传数组绝对用指针... 考虑点分治 在点分的时候,把相同的颜色的在一起合并 之后,把不同颜色依次合并 我们可以用单调队列做到单次合并$O(n + m)$ 如果我们按照深度大小来合并,那么由于每次都 ...
- 洛谷1087 FBI树 解题报告
洛谷1087 FBI树 本题地址:http://www.luogu.org/problem/show?pid=1087 题目描述 我们可以把由“0”和“1”组成的字符串分为三类:全“0”串称为B串,全 ...
- 洛谷P3018 [USACO11MAR]树装饰Tree Decoration
洛谷P3018 [USACO11MAR]树装饰Tree Decoration树形DP 因为要求最小,我们就贪心地用每个子树中的最小cost来支付就行了 #include <bits/stdc++ ...
- NOIP2017提高组Day2T3 列队 洛谷P3960 线段树
原文链接https://www.cnblogs.com/zhouzhendong/p/9265380.html 题目传送门 - 洛谷P3960 题目传送门 - LOJ#2319 题目传送门 - Vij ...
随机推荐
- noj加1乘2平方
广度优先搜索典例 00 题目 描述: 最简单的队列的使用#include <iostream>#include <queue>using namespace std;queue ...
- 【UE4】虚幻引擎技术直播汇总(含中英文直播)
B站虚幻引擎官方账号 中文直播 [中文直播]第35期 | 使用GIS在UE中创造真实地球风貌 | Epic 周澄清 [中文直播]第34期 | 包教包会的Epic MegaGrants申请之道 | Ep ...
- 第三次Scrum Metting
日期:2021年4月27日会议主要内容概述:确定后端和前端接口,前端讨论画图页面,解决两处画图问题 一.进度情况# 组员 负责 两日内已完成的工作 后两日计划完成的工作 工作中遇到的困难 徐宇龙 后端 ...
- oo第一单元学习总结
写在开头: 第一次接触面向对象思想和java语言,在学习以及完成作业的过程经历了一个比较痛苦的过程, 虽然在每次写作业时总是会有一些小小的抱怨,虽然写出的代码还是很差, 但是看到自己有所进步,还是感觉 ...
- 【学习笔记】Vizing 定理
图染色问题的经典结论 定义 称一个边染色方案合法当且仅当每个顶点连出的所有边的颜色都互不相同,如果此时出现了 \(k\) 个颜色那么称该方案是图的一组 \(k\) 染色 一张无向图的边着色数为最小的 ...
- OSI参考模型(应用层、表示层、会话层、传输层、网络层、数据链路层、物理层)
文章转自:https://blog.csdn.net/weixin_43914604/article/details/104589085 学习课程:<2019王道考研计算机网络> 学习目的 ...
- uni-app 安卓离线打包详细教程
借鉴 uni-app官方给出的文章http://ask.dcloud.net.cn/article/508(虽说是04年的) 预备环境 AndroidStudio开发环境,要求安装Android4.0 ...
- DDD领域驱动设计-项目包结构说明-Ⅳ
基于DDD领域驱动设计的思想,在开发具体系统时,需要先建立不同的层级包.主要是梳理不同层面(应用层,领域层,基础设施层,展示层)包括的功能目录,每一个层面应该包括哪些模块.本例所讲述的分层是DDD落 ...
- 从零开始的DIY智能家居 - 基于 ESP32 的智能浇水器
前言 上次 土壤湿度传感器 完成之后,就立下一个 flag 要搭建一个智慧浇水的智能场景,现在终于有时间填坑了!(o゚▽゚)o 智慧浇水场景的核心设备有三个: 检测土壤状态的:土壤湿度传感器 通过这个 ...
- tarjan知识点梳理
tarjan在图论中还是挺重要的.这里就简要的梳理一下tarjan的知识点. tarjan算法与无向图连通性. 首先说一下图中割点和桥的定义. 桥:也称割边,定义类似,在无向图中,若去掉某条边,导致整 ...