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]树的难题的更多相关文章

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

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

  2. BZOJ4860 BJOI2017 树的难题 点分治、线段树合并

    传送门 只会线段树……关于单调队列的解法可以去看“重建计划”一题. 看到路径长度$\in [L,R]$考虑点分治.可以知道,在当前分治中心向其他点的路径中,始边(也就是分治中心到对应子树的根的那一条边 ...

  3. bzoj 4860 [BeiJing2017]树的难题

    题面 https://www.lydsy.com/JudgeOnline/problem.php?id=4860 题解 点分治 设当前重心为v 假设已经把所有边按照出发点第一关键字, 颜色第二关键字排 ...

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

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

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

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

  6. BZOJ3257 : 树的难题

    设$f[x][i][j]$表示以$x$为根的子树,与$x$连通部分有$i$个黑点,$j$个白点,不联通部分都是均衡的最小代价.若$i>1$,则视作$1$:若$j>2$,则视作$2$. 然后 ...

  7. 【XSY2307】树的难题

    Description Solution 看到这种路径统计问题,一般就想到要用点分治去做. 对于每个重心\(u\),统计经过\(u\)的合法的路径之中的最大值. 第一类路径是从\(u\)出发的,直接逐 ...

  8. 并不对劲的loj2179:p3714:[BJOI2017]树的难题

    题目大意 有一棵树,\(n\)(\(n\leq2*10^5\))个点,每条边\(i\)有颜色\(w_i\),共有\(m\)(\(m\leq n\))种颜色,第\(i\)种颜色的权值是\(c_i\)(\ ...

  9. [JZOJ3347] 【NOI2013模拟】树的难题

    题目 题目大意 给你一棵树,每个节点有三种黑.白.灰三种颜色. 你要割掉一些边(每条边被割需要付出一定的代价),使得森林的每棵树满足: 没有黑点或至多一个白点. 思考历程 这题一看就知道是一个树形DP ...

随机推荐

  1. 【PBR的基本配置】

    PBR基于策略路由的配置 一:基于报文协议的本地PBR 1:首先进行理论分析:在SW1上利用基于报文报文协议类型的PBR,在sw1与sw3的连接链路上,利用acl制定允许tcp的报文通过3000,并与 ...

  2. linux中安装node

    1.去官网下载和自己系统匹配的文件: 英文网址:https://nodejs.org/en/download/ 中文网址:http://nodejs.cn/download/ 通过 uname -a ...

  3. ELK的简述安装

    一.ElasticSearch集群的安装及其配置 https://www.cnblogs.com/gentle-awen/p/10000801.html 可视化x-pack安装: https://ww ...

  4. python基础之初识

    一. 计算机是什么 基本组成: 主板+cpu+内存 cpu: 主频, 核数(16) 内存:大小(8G, 16G, 32G) 型号: DDR3, DDR4, DDR5, 主频(海盗船,玩家国度) 显卡: ...

  5. ruby 数据类型Range

    范围(Range)无处不在:a 到 z. 0 到 9.等等.Ruby 支持范围,并允许我们以不同的方式使用范围: 作为序列的范围 作为条件的范围 作为间隔的范围 作为序列的范围 (1..5) #==& ...

  6. mybatis 打印SQL

    如果使用的是application.properties文件,加入如下配置: #打印SQL logging.level.com.jn.ssr.supererscuereporting.dao=debu ...

  7. Kubernetes-GC

    Kubernetes集群中垃圾回收(Garbage Collection)机制由kubelet完成.kubelet定期清理不再使用的容器和镜像,每分钟进行一次容器的GC操作,每五分钟进行一次镜像的GC ...

  8. 【POJ】1008 Maya Calendar

    参考:https://blog.csdn.net/u011392408/article/details/28866779 https://blog.csdn.net/qq_36424540/artic ...

  9. Uber:中国市场两年内不考虑盈利,每年补贴10亿美金

    滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://www.cnblogs.com/mfry ...

  10. LeetCode:9. Palindromic Number(Medium)

    原题链接:https://leetcode.com/problems/palindrome-number/description/ 1. 题目要求:判断一个int类型整数是否是回文,空间复杂度O(1) ...