[bzoj4860] [BeiJing2017]树的难题
Description
给你一棵 n 个点的无根树。树上的每条边具有颜色。 一共有 m 种颜色,编号为 1 到 m。第 i 种颜色的权值为
ci。对于一条树上的简单路径,路径上经过的所有边按顺序组成一个颜色序列,序列可以划分成若干个相同颜色段
。 定义路径权值为颜色序列上每个同颜色段的颜色权值之和。请你计算,经过边数在 l 到 r 之间的所有简单路
径中, 路径权值的最大值。
Input
第一行, 四个整数 n, m, l, r。
第二行, n 个整数 c1, c2, ……, cm,由空格隔开。依次表示每个颜色的权值。
接下来 n-1 行,每行三个整数 u, v, c,表示点 u 和点 v 之间有一条颜色为 c 的边。
Output
输出一行, 一个整数, 表示答案。
Sample Input
5 3 1 4
-1 -5 -2
1 2 1
1 3 1
2 4 2
2 5 3
Sample Output
-1
Solution
统计链上信息,上点分治。
对于当前的分治中心,把边按颜色\(sort\)一遍,然后开两个线段树,对于颜色相同的边用一颗线段树统计,不同的也开一颗,做完一种颜色就把两颗线段树合并一下,然后清空就好了。
复杂度\(O(n\log^2n)\),然后凭借信仰过掉此题(跑的还蛮快的)
不过正解好像是单调队列,我太弱了不会QAQ
#include<bits/stdc++.h>
using namespace std;
inline int max(int x,int y) {return x>y?x:y;}
#define il inline
il void read(int &x) {
x=0;int f=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
}
il void print(int x) {
if(x<0) putchar('-'),x=-x;
if(!x) return ;print(x/10),putchar(x%10+48);
}
il void write(int x) {if(!x) putchar('0');else print(x);putchar('\n');}
const int maxn = 6e5+10;
const int inf = 1e9;
int n,m,l,r,tot,st[maxn],ed[maxn],ls[maxn<<2],rs[maxn<<2],tr[maxn<<2],cnt;
struct edge{
int fr,to,w;
int operator < (const edge &rhs) const {
return fr<rhs.fr||(fr==rhs.fr&&w<rhs.w);
}
}e[maxn<<1];
il void add(int u,int v,int w) {e[++tot]=(edge){u,v,w};}
il void ins(int u,int v,int w) {add(u,v,w),add(v,u,w);}
#define mid ((l+r)>>1)
namespace Segment_Tree {
void modify(int &p,int l,int r,int x,int v) {
if(!p) p=++cnt,ls[p]=rs[p]=0,tr[p]=-inf;
else tr[p]=max(tr[p],v);
if(l==r) return ;
if(x<=mid) modify(ls[p],l,mid,x,v);
else modify(rs[p],mid+1,r,x,v);
}
int query(int p,int l,int r,int x,int y) {
if(!p) return -inf;
if(x<=l&&r<=y) return tr[p];
int ans=-inf;
if(x<=mid) ans=max(ans,query(ls[p],l,mid,x,y));
if(y>mid) ans=max(ans,query(rs[p],mid+1,r,x,y));
return ans;
}
int merge(int x,int y) {
if(!x||!y) return x+y;
ls[x]=merge(ls[x],ls[y]);
rs[x]=merge(rs[x],rs[y]);
tr[x]=max(tr[x],tr[y]);
return x;
}
}
#undef mid
using namespace Segment_Tree;
namespace Tree {
int rt,f[maxn],sz[maxn],size,vis[maxn],data_cnt,c[maxn],ans,ss[maxn];
void get_rt(int x,int fa) {
sz[x]=1,f[x]=1;
for(int i=st[x];i<=ed[x];i++)
if(e[i].to!=fa&&(!vis[e[i].to]))
get_rt(e[i].to,x),sz[x]+=sz[e[i].to],f[x]=max(f[x],sz[e[i].to]);
f[x]=max(f[x],size-sz[x]);
if(f[rt]>f[x]) rt=x;
}
struct data {int dep,dis;}d[maxn];
void get_data(int x,int fa,int dep,int col,int sum) {
if(dep>r) return ;
for(int i=st[x];i<=ed[x];i++) {
if(e[i].to==fa||vis[e[i].to]) continue;
d[++data_cnt]=(data){dep+1,sum+((col==e[i].w)?0:c[e[i].w])};
get_data(e[i].to,x,dep+1,e[i].w,sum+((col==e[i].w)?0:c[e[i].w]));
}
}
void solve(int x) {
vis[x]=1;int r1=0,r2=cnt=0;
for(int i=st[x];i<=ed[x];++i) {
if(e[i].w!=e[i-1].w&&i!=st[x]) r1=merge(r1,r2),r2=0;
if(vis[e[i].to]) continue;
data_cnt=0;
d[++data_cnt]=(data){1,c[e[i].w]};
get_data(e[i].to,x,1,e[i].w,c[e[i].w]);
ss[i]=data_cnt;
for(int j=1;j<=data_cnt;++j) {
if(d[j].dep>r) continue;
if(d[j].dep<r) {
ans=max(ans,d[j].dis+query(r2,1,n,max(1,l-d[j].dep),r-d[j].dep)-c[e[i].w]);
ans=max(ans,d[j].dis+query(r1,1,n,max(1,l-d[j].dep),r-d[j].dep));
}
if(d[j].dep>=l) ans=max(ans,d[j].dis);
}
for(int j=1;j<=data_cnt;++j)
if(d[j].dep<r) modify(r2,1,n,d[j].dep,d[j].dis);
}
for(int i=st[x];i<=ed[x];++i) {
if(vis[e[i].to]) continue;
rt=0,size=ss[i],get_rt(e[i].to,x);
solve(rt);
}
}
}
using namespace Tree;
int main() {
read(n),read(m),read(l),read(r);ans=-inf;
for(int i=1;i<=m;i++) read(c[i]);
for(int i=1,x,y,z;i<n;i++) read(x),read(y),read(z),ins(x,y,z);
sort(e+1,e+n*2-1);int p=1;
for(int i=1;i<=n;i++) {
st[i]=p;while(e[p].fr==i&&p<=n*2-2) p++;ed[i]=p-1;
}
rt=0,f[0]=maxn+1,size=n,get_rt(1,0),solve(rt);write(ans);
return 0;
}
[bzoj4860] [BeiJing2017]树的难题的更多相关文章
- BZOJ4860 Beijing2017树的难题(点分治+单调队列)
考虑点分治.对子树按照根部颜色排序,每次处理一种颜色的子树,对同色和不同色两种情况分别做一遍即可,单调队列优化.但是注意到这里每次使用单调队列的复杂度是O(之前的子树最大深度+该子树深度),一不小心就 ...
- BZOJ4860 BJOI2017 树的难题 点分治、线段树合并
传送门 只会线段树……关于单调队列的解法可以去看“重建计划”一题. 看到路径长度$\in [L,R]$考虑点分治.可以知道,在当前分治中心向其他点的路径中,始边(也就是分治中心到对应子树的根的那一条边 ...
- bzoj 4860 [BeiJing2017]树的难题
题面 https://www.lydsy.com/JudgeOnline/problem.php?id=4860 题解 点分治 设当前重心为v 假设已经把所有边按照出发点第一关键字, 颜色第二关键字排 ...
- [BJOI2017]树的难题 点分治 线段树
题面 [BJOI2017]树的难题 题解 考虑点分治. 对于每个点,将所有边按照颜色排序. 那么只需要考虑如何合并2条链. 有2种情况. 合并路径的接口处2条路径颜色不同 合并路径的接口处2条路径颜色 ...
- [BJOI2017]树的难题 点分治,线段树合并
[BJOI2017]树的难题 LG传送门 点分治+线段树合并. 我不会写单调队列,所以就写了好写的线段树. 考虑对于每一个分治中心,把出边按颜色排序,这样就能把颜色相同的子树放在一起处理.用一棵动态开 ...
- BZOJ3257 : 树的难题
设$f[x][i][j]$表示以$x$为根的子树,与$x$连通部分有$i$个黑点,$j$个白点,不联通部分都是均衡的最小代价.若$i>1$,则视作$1$:若$j>2$,则视作$2$. 然后 ...
- 【XSY2307】树的难题
Description Solution 看到这种路径统计问题,一般就想到要用点分治去做. 对于每个重心\(u\),统计经过\(u\)的合法的路径之中的最大值. 第一类路径是从\(u\)出发的,直接逐 ...
- 并不对劲的loj2179:p3714:[BJOI2017]树的难题
题目大意 有一棵树,\(n\)(\(n\leq2*10^5\))个点,每条边\(i\)有颜色\(w_i\),共有\(m\)(\(m\leq n\))种颜色,第\(i\)种颜色的权值是\(c_i\)(\ ...
- [JZOJ3347] 【NOI2013模拟】树的难题
题目 题目大意 给你一棵树,每个节点有三种黑.白.灰三种颜色. 你要割掉一些边(每条边被割需要付出一定的代价),使得森林的每棵树满足: 没有黑点或至多一个白点. 思考历程 这题一看就知道是一个树形DP ...
随机推荐
- 洛谷 T51922 父子
题目描述 对于全国各大大学的男生寝室,总是有各种混乱的父子关系. 那么假设现在我们一个男生寝室有不同的 nn 个人,每个人都至多有一个“爸爸”,可以有多个“儿子”,且有且只有一个人没有“爸爸”(毕竟是 ...
- laravel 基础 --内置函数
简介 Laravel 自带了一系列 PHP 辅助函数,很多被框架自身使用,如果你觉得方便的话也可以在代码中使用它们. https://laravelacademy.org/post/8967.html ...
- 一张表搞清楚 php 的 is_null、empty、isset的区别
isset 判断变量是否已存在 empty 判断变量是否为空或为0 is_null 判断变量是否为NULL 变量 empty is_null isset $a=”” true false true $ ...
- 004---基于TCP的套接字
基于TCP的套接字 tcp是基于链接的,必须先启动服务端,然后再启动客户端去连接服务端. 之前实现的简单套接字就是基于TCP的,但是只能实现收发消息一次.服务器与客户端都断开了.不够过瘾. 通信循环版 ...
- maven 添加自己下载的jar包到本地仓库
1.在pom文件中添加依赖,其中groupId等变量都自拟. 例如: 2.在命令行执行以下命令,提示build success即表示安装成功. mvn install:install-file -Dg ...
- 为什么我要放弃javaScript数据结构与算法(第一章)—— JavaScript简介
数据结构与算法一直是我算比较薄弱的地方,希望通过阅读<javaScript数据结构与算法>可以有所改变,我相信接下来的记录不单单对于我自己有帮助,也可以帮助到一些这方面的小白,接下来让我们 ...
- springboot2.x+maven+proguard代码混淆
由于需要将源码打包做代码混淆,选择proguard,开始使用各种问题,各种jar包版本问题,但最终成功了,记录一下,也希望能够帮助大家 在pom中添加代码: <build> <fin ...
- LeetCode:11. ContainerWithWater(Medium)
原题链接:https://leetcode.com/problems/container-with-most-water/description/ 题目要求:给定n个非负整数a1,a2,...,an ...
- 配置ORACLE的PRO*C环境
1.访问数据库的方法 在ORACLE数据库管理和系统中,有三种访问数据库的方法: ⑴.用SQL*Plus, 它有SQL命令以交互的应用程序访问数据库: ⑵.用第四代语言应用开发工具开 ...
- 四大IO抽象类
四大IO抽象类 InputStream/OutputStream和Reader/writer类是所有IO流类的抽象父类,我们有必要简单了解一下这个四个抽象类的作用.然后,通过它们具体的子类熟悉相 ...