题面

https://www.lydsy.com/JudgeOnline/problem.php?id=4860

题解

点分治

设当前重心为v

假设已经把所有边按照出发点第一关键字, 颜色第二关键字排序

对于当前的v 我们顺次考虑他的出边

设当前出边(v,nw) 颜色 col

我们枚举nw的出边

对于一条nw的出边而言, 分为两种情况

1. 颜色与col相同   用线段树维护深度及对应的最值,查询到最大值即可 (v,nw)没有贡献

2. 颜色与col不同   用另一棵线段树维护深度以及与(当前节点的连向其父节点的边的颜色)不同的(连向子节点的边)所对应的子节点对应的子树之内的最值 加上col的权值

向上的时候 将线段树合并

Code

 #include <cstdio>
#include <cctype>
#include <algorithm>
const int maxn=,inf=;
int ans,n,x,y,z,i,m,l,r,c[maxn*],cnt;
inline int max(int a,int b){
return a>b?a:b;
}
inline void up(int&a,const int&b){
if(a<b)a=b;
}
inline int getint(){
char c=getchar();
int x=,neg=;
while(!isdigit(c)){
if(c=='-')neg=-;
c=getchar();
}
while(isdigit(c)){
x=x*+c-;
c=getchar();
}
return x*neg;
}
struct edge{
int from,to,color;
}e[maxn<<];
struct data{
int dep,sum;
};
struct node{
int v,lc,rc;
}a[maxn*];
int merge(int x,int y){
if(!x || !y )return x|y;
a[x].lc=merge(a[x].lc,a[y].lc);
a[x].rc=merge(a[x].rc,a[y].rc);
up(a[x].v,a[y].v);
return x;
}
void add(int&i,int rl,int rr,int x,int v){
if(!i)a[i=++cnt]=(node){v,,};
else up(a[i].v,v);
if(rl<rr){
int m=(rl+rr)>>;
if(x>m)add(a[i].rc,m+,rr,x,v);
else add(a[i].lc,rl,m,x,v);
}
}
int query(int i,int rl,int rr,int l,int r){
if(!i)return -inf;
if(rl==l && rr==r)return a[i].v;
int m=(rl+rr)>>;
if(l>m)return query(a[i].rc,m+,rr,l,r);
else if(r<=m)return query(a[i].lc,rl,m,l,r);
else return max(query(a[i].lc,rl,m,l,m),query(a[i].rc,m+,rr,m+,r));
}
struct tree{
int xb,h[maxn],n,size[maxn],f[maxn],rt,sum,dep[maxn],ll,ss[maxn];
bool b[maxn];
data w[maxn];
void addedge(int x,int y,int z){
e[++xb]=(edge){y,x,z};
e[++xb]=(edge){x,y,z};
}
void dfs(int x,int fa){
size[x]=f[x]=;
for(int i=h[x];i<h[x+];++i){
int y=e[i].to;
if(y!=fa && !b[y]){
dfs(y,x);
size[x]+=size[y];
up(f[x],size[y]);
}
}
up(f[x],sum-size[x]);
if(f[rt]>f[x])rt=x;
}
void got(int x,int fa,int dep,int color,int sum){
for(int y,i=h[x];i<h[x+];++i){
y=e[i].to;
if(y!=fa && !b[y]){
if(e[i].color==color)w[++ll]=(data){dep+,sum};
else w[++ll]=(data){dep+,sum+c[e[i].color]};
got(e[i].to,x,dep+,e[i].color,w[ll].sum);
}
}
}
void solve(int x){
b[x]=;
int i,rt1=,rt2=cnt=,j;
for(i=h[x];i<h[x+];++i){
if(i>h[x] && e[i].color>e[i-].color)rt1=merge(rt1,rt2),rt2=;
if(!b[e[i].to]){
w[ll=]=(data){,c[e[i].color]};
got(e[i].to,x,,e[i].color,c[e[i].color]);
ss[i]=ll;
for(j=;j<=ll;++j)if(w[j].dep<=r){
if(w[j].dep>=l)up(ans,w[j].sum);
if(w[j].dep<r){
up(ans,query(rt1,,n,max(,l-w[j].dep),r-w[j].dep)+w[j].sum);
up(ans,query(rt2,,n,max(,l-w[j].dep),r-w[j].dep)-c[e[i].color]+w[j].sum);
}
}
for(j=;j<=ll;++j)if(w[j].dep<=r)add(rt2,,n,w[j].dep,w[j].sum);
}
}
for(i=h[x];i<h[x+];++i)
if(!b[e[i].to]){
sum=ss[i];
rt=;
dfs(e[i].to,x);
solve(rt);
}
}
}t;
bool cmp(const edge&a,const edge&b){
return a.from==b.from?a.color<b.color:a.from<b.from;
}
int main(){
//freopen("input","r",stdin);
a[].v=-inf;
t.n=n=getint();
m=getint();
l=getint();
r=getint();
for(i=;i<=m;++i)c[i]=getint();
for(i=;i<n;++i){
x=getint();
y=getint();
z=getint();
t.addedge(x,y,z);
}
std::sort(e+,e+((n-)*)+,cmp);
for(i=;i<=((n-)<<);++i)
if(!t.h[e[i].from])t.h[e[i].from]=i;
t.h[n+]=(n-)<<|;
t.f[t.rt=]=inf;
t.sum=n;
ans=-inf;
t.dfs(,);
t.solve(t.rt);
printf("%d\n",ans);
}

Review

一开始以为是树形dp 后来发现那是错的

还可以用单调队列过 好像更简单

bzoj 4860 [BeiJing2017]树的难题的更多相关文章

  1. [bzoj4860] [BeiJing2017]树的难题

    Description 给你一棵 n 个点的无根树.树上的每条边具有颜色. 一共有 m 种颜色,编号为 1 到 m.第 i 种颜色的权值为 ci.对于一条树上的简单路径,路径上经过的所有边按顺序组成一 ...

  2. BZOJ4860 Beijing2017树的难题(点分治+单调队列)

    考虑点分治.对子树按照根部颜色排序,每次处理一种颜色的子树,对同色和不同色两种情况分别做一遍即可,单调队列优化.但是注意到这里每次使用单调队列的复杂度是O(之前的子树最大深度+该子树深度),一不小心就 ...

  3. BZOJ 3672[NOI2014]购票(树链剖分+线段树维护凸包+斜率优化) + BZOJ 2402 陶陶的难题II (树链剖分+线段树维护凸包+分数规划+斜率优化)

    前言 刚开始看着两道题感觉头皮发麻,后来看看题解,发现挺好理解,只是代码有点长. BZOJ 3672[NOI2014]购票 中文题面,题意略: BZOJ 3672[NOI2014]购票 设f(i)f( ...

  4. [BJOI2017]树的难题 点分治 线段树

    题面 [BJOI2017]树的难题 题解 考虑点分治. 对于每个点,将所有边按照颜色排序. 那么只需要考虑如何合并2条链. 有2种情况. 合并路径的接口处2条路径颜色不同 合并路径的接口处2条路径颜色 ...

  5. BZOJ 2243 染色 | 树链剖分模板题进阶版

    BZOJ 2243 染色 | 树链剖分模板题进阶版 这道题呢~就是个带区间修改的树链剖分~ 如何区间修改?跟树链剖分的区间询问一个道理,再加上线段树的区间修改就好了. 这道题要注意的是,无论是线段树上 ...

  6. BZOJ.1036 [ZJOI2008]树的统计Count ( 点权树链剖分 线段树维护和与最值)

    BZOJ.1036 [ZJOI2008]树的统计Count (树链剖分 线段树维护和与最值) 题意分析 (题目图片来自于 这里) 第一道树链剖分的题目,谈一下自己的理解. 树链剖分能解决的问题是,题目 ...

  7. [BJOI2017]树的难题 点分治,线段树合并

    [BJOI2017]树的难题 LG传送门 点分治+线段树合并. 我不会写单调队列,所以就写了好写的线段树. 考虑对于每一个分治中心,把出边按颜色排序,这样就能把颜色相同的子树放在一起处理.用一棵动态开 ...

  8. [BZOJ 4771]七彩树(可持久化线段树+树上差分)

    [BZOJ 4771]七彩树(可持久化线段树+树上差分) 题面 给定一棵n个点的有根树,编号依次为1到n,其中1号点是根节点.每个节点都被染上了某一种颜色,其中第i个节点的颜色为c[i].如果c[i] ...

  9. BZOJ 2402 陶陶的难题II (树链剖分、线段树、凸包、分数规划)

    毒瘤,毒瘤,毒瘤-- \(30000\)这个数据范围,看上去就是要搞事的啊... 题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=2402 ...

随机推荐

  1. 写码时应该缩进使用 tab 还是空格?

    对于程序员来说,其实Tab和空格远远不只是“立场”问题那么简单. 在不同的编辑器里tab的长度可能不一致,所以在一个编辑器里用tab设置缩进后,在其它编辑器里看可能缩进就乱了.空格不会出现这个问题,因 ...

  2. thinkphp Class 'PDO' not found 错误

    thinkphp Class 'PDO' not found 错误,原因mysql5.7.26缺少pdo驱动,需要安装php的pdo和pdo_mysql扩展 本文以centOS为例 1.进入PHP源码 ...

  3. Mac版的idea部分按钮失效的解决方案

    问题描述:调整了一下idea中jdk的路径,之后idea就无法打开新项目了,最好发现idea中的顶部菜单全部失效 解决过程: 1.把idea的jdk的路径调回去,无效 2.重启idea,无效 3.重启 ...

  4. SQL常见问题及解决备忘

    1.mysql中:you cant't specify tartget table for update in from clause 错误 含义:在同一语句中update或delete某张表的时候, ...

  5. 解决gradle多模块依赖在Idea中能运行,gradle build失败的问题。

    最近需要初始化一个SpringBoot新项目遇到一个问题就是:项目中有多个子模块,使用gradle依赖管理成功. 项目结构如下: project --module1     --module2我的mo ...

  6. VS 预先生成事件命令

    宏 说明 $(ConfigurationName) 当前项目配置的名称(例如,“Debug|Any CPU”). $(OutDir) 输出文件目录的路径,相对于项目目录.这解析为“输出目录”属性的值. ...

  7. JavaScript数组的某些操作(一)

    在软件开发的过程中JavaScript的编程在所难免.当中对数组的操作尤为常见,这里介绍一下和JavaScript数组相关的某些操作: 1.删除并返回数组的第一个元素--shift方法: <!D ...

  8. Oracle数据库案例整理-Oracle系统执行时故障-断电导致数据文件状态变为RECOVER

    1.1      现象描写叙述异常断电.数据库数据文件的状态由ONLINE变为RECOVER. 系统显演示样例如以下信息:SQL>selectfile_name,tablespace_name, ...

  9. redis12-----redis 与关系型数据库的对比

    书和书签系统 create table book ( bookid int, title ) )engine myisam charset utf8; insert into book values ...

  10. POJ1511 Invitation Cards —— 最短路spfa

    题目链接:http://poj.org/problem?id=1511 Invitation Cards Time Limit: 8000MS   Memory Limit: 262144K Tota ...