[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 ...
随机推荐
- SQL命令(三)
数据完整性约束 1)数据完整性约束包含:实体完整性.参照完整性.用户定义完整性. CREATE TABLE table( id INT NOT NULL AUTO_INCREMENT PRIMARY ...
- MR执行流程
1.Map任务处理 1.1 读取HDFS中的文件.每一行解析成一个<k,v>.每一个键值对调用一次map函数. <0,hello you> <10,hello me& ...
- Python学习 :格式化输出
方式一:使用占位符 % 常用占位符:% s (s = string 字符串) % d (d = digit 整数(十进制)) % f ( f = float 浮点数) na ...
- 解决Pycharm无法使用已经安装Selenium的问题
重要:参考资料 当前版本 python版本:2.7 pycharm: 2017 原来本机是已经安装了2.7和selenium,新安装了一个pycharm的ide,于是selenium总是安装报错.At ...
- tarnado源码解析系列一
目录 tarnado tarnado源码安装 tarnado测试程序 application类的解析 一. tarnado简介 最近在学习Python,无意间接触到的tarnado,感觉tarnado ...
- 列表排序之NB三人组附加一个希尔排序
NB三人组之 快速排序 def partition(li, left, right): tmp = li[left] while left < right: while left < ri ...
- Sql Server 表间对应关系
<1>.关联映射:一对多/多对一 存在最普遍的映射关系,简单来讲就如球员与球队的关系:一对多:从球队角度来说一个球队拥有多个球员 即为一对多多对一:从球员角度来说多个球员属于一个球队 即为 ...
- 最后一片蓝海的终极狂欢-写在Win10发布前夕
作为一名Windows8.x+系统平台从业者,从工作伊始,耳边不断充斥着Windows将走向没落的言论,Win10今日晚些时候即将发布,笔者借此机会,说说自己的看法. 早在2012年的时候,IDC曾预 ...
- spring location设置本地路径
<context:property-placeholder location="file:D:/jdbc.properties"/> 直接在路径前加上 file:
- lua敏感词过滤
--过滤敏感词(如果onlyKnowHas为true,表示只想知道是否存在敏感词,不会返回过滤后的敏感词,比如用户注册的时候,我们程序是只想知道用户取的姓名是否包含敏感词的(这样也能提高效率,检测到有 ...