[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 ...
随机推荐
- Bad escape character ‘ygen’ 错误原因!
ssh-keygen -t rsa -C “邮箱” ssh-keygen 命令中间没有空格,如果在ssh后面加上空格,会得到Bad escape character ‘ygen’.的错误.
- ruby中将数字转化为字符串格式时差
工作中有时候会碰到需要把数值展示成比较直观的时间差格式,divmod方法很适合做这个操作. divmod #输出商和余数的数组 60.divmod(50) #=> [1, 10 ...
- unity独立游戏开发日志2018/09/22
f::很头痛之前rm做的游戏在新电脑工程打不开了...只能另起炉灶... 还不知道新游戏叫什么名...暂且叫方块世界.(素材已经授权) 首先是规划下场景和素材文件夹的建立. unity常用的文件夹有: ...
- dotnet core 数据库
dotnet core 数据库 程序开发过程中,需要使用数据对数据进行存储,分析等.通常而言都会使用ORM来实现关系数据库与实体对象的转化,过使用描述对象和数据库之间映射的元数据,将程序中的对象自动持 ...
- Vue 去脚手架插件,自动加载vue文件
接上回 一些本质 本质上,去脚手架也好,读取vue文件也好,无非是维护options,每个Vue对象的初始化配置对象不触及Vue内部而言,在外部想怎么改都是可以的,只要保证options的正确,一切都 ...
- torndb在python3中运用
#连接数据库:db = torndb.Connect() #查询一条的数据get() #查询多行的数据query() #创建数据表,数据库execute() #插入一条数据:sql = "i ...
- 让Dreamweaver支持cshtml (MVC Razor环境)
介绍:让Dreamweaver支持cshtml 正文: 如题,刚才搜了很久,都搜不到答案,幸好得到“包大人”(同事)的帮助,才得以解决. DW支持很多文件类型的代码提示,可是类型太多,不可能全部都有, ...
- Linux-Shell脚本编程-学习-7-总结前面开启后面的学习
国庆前期后国庆回来也都比较忙,把书一放下,在那起来,就难了,发现好多都开始忘记了,今天好不容易硬着头片看来两章,算是马马虎虎的把前面的基础性质的只是看完了吧. 后面讲开始学习Shell编程的高级阶段, ...
- 剑指offer-调整数组顺序使奇数位于偶数前面13
题目描述 输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变. class Solu ...
- day-9 sklearn库和python自带库实现最近邻KNN算法
K最近邻(k-Nearest Neighbor,KNN)分类算法,是一个理论上比较成熟的方法,也是最简单的机器学习算法之一.该方法的思路是:如果一个样本在特征空间中的k个最相似(即特征空间中最邻近)的 ...