[BJOI2017]树的难题

LG传送门

点分治+线段树合并。

我不会写单调队列,所以就写了好写的线段树。

考虑对于每一个分治中心,把出边按颜色排序,这样就能把颜色相同的子树放在一起处理。用一棵动态开点线段树维护颜色不同的子树的信息,另一棵动态开点线段树维护颜色相同的子树的信息,同时按照题目要求更新答案。当子树颜色变化时,就把第二棵线段树合并到第一棵里面去就好了。

代码实现有点繁琐,我调了很久。。。

#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
#include<vector>
#define R register
#define I inline
#define Z first
#define Y second
using namespace std;
const int S=200003,M=6000003,inf=0x3f3f3f3f;
char buf[1000000],*p1,*p2;
I char gc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,S,stdin),p1==p2)?EOF:*p1++;}
I int rd(){
R int f=0,b=1; R char c=gc();
while((c<48||c>57)&&c!=45) c=gc();
if(c==45) b=0,c=gc();
while(c>47&&c<58) f=f*10+(c^48),c=gc();
return b?f:~f+1;
}
vector<pair<int,int> > g[S];
struct T{int l,r,f;}a[M];
int c[S],s[S],t[S],h[S],v[S],n,m,e,L,U,u,r,o=-inf,A,B;
I int max(int x,int y){return x>y?x:y;}
I void add(int x,int y,int z){g[x].push_back(make_pair(z,y)),++s[x];}
I void ini(){a[++e].f=-inf,a[e].l=a[e].r=0;}
int mrg(int k,int t){
if(!k) return t;
if(!t) return k;
a[k].f=max(a[k].f,a[t].f),a[k].l=mrg(a[k].l,a[t].l),a[k].r=mrg(a[k].r,a[t].r);
return k;
}
void ins(int &k,int l,int r,int x,int v){
if(!k) ini(),k=e;
if(l==r){a[k].f=max(a[k].f,v); return ;}
R int m=l+r>>1;
if(x<=m) ins(a[k].l,l,m,x,v);
else ins(a[k].r,m+1,r,x,v);
a[k].f=max(a[a[k].l].f,a[a[k].r].f);
}
int qry(int k,int l,int r,int x,int y){
if(!k) return -inf;
if(x<=l&&r<=y) return a[k].f;
R int m=l+r>>1,o=-inf;
if(x<=m) o=max(o,qry(a[k].l,l,m,x,y));
if(m<y) o=max(o,qry(a[k].r,m+1,r,x,y));
return o;
}
void gsz(int x,int f){
t[x]=1;
for(R int i=0,y;i<s[x];++i)
if(!v[y=g[x][i].Y]&&y^f)
gsz(y,x),t[x]+=t[y];
}
void grt(int x,int f,int a){
R int i,y,m=0;
for(i=0;i<s[x];++i)
if(!v[y=g[x][i].Y]&&y^f)
grt(y,x,a),m=max(m,t[y]);
m=max(m,a-t[x]);
if(m<u) u=m,r=x;
}
void dfs(int x,int f,int r,int l,int d){
if(l>U) return ;
h[l]=max(h[l],d);
for(R int i=0,y,z;i<s[x];++i)
if(!v[y=g[x][i].Y]&&y^f)
z=g[x][i].Z,dfs(y,x,z,l+1,z^r?d+c[z]:d);
}
void dac(int x){
R int i,j,y,z,l;
e=A=B=0,u=n,gsz(x,0),grt(x,0,t[x]),gsz(r,0),v[r]=1,l=r;
for(i=0;i<s[r];++i)
if(!v[y=g[r][i].Y]){
z=g[r][i].Z,memset(h,-0x3f,sizeof(int)*(t[y]+1));
if(B&&z^g[r][i-1].Z)
A=mrg(A,B),B=0;
dfs(y,r,z,1,c[z]);
for(j=1;j<=t[y]&&j<U&&h[j]^h[0];++j)
o=max(max(o,L<=j&&j<=U?h[j]:-inf),max(qry(A,1,U,max(1,L-j),U-j),qry(B,1,U,max(1,L-j),U-j)-c[z])+h[j]);
o=max(o,h[U]);
for(j=1;j<=t[y]&&j<U&&h[j]^h[0];++j)
ins(B,1,U,j,h[j]);
}
for(i=0;i<s[l];++i)
if(!v[y=g[l][i].Y])
dac(y);
}
int main(){
R int i,x,y,z;
n=rd(),m=rd(),L=rd(),U=rd();
for(i=1;i<=m;++i)
c[i]=rd();
for(i=1;i<n;++i)
x=rd(),y=rd(),z=rd(),add(x,y,z),add(y,x,z);
for(i=1;i<=n;++i)
sort(g[i].begin(),g[i].end());
memset(h,-0x3f,sizeof h),a[0].f=-inf,dac(1),printf("%d",o);
return 0;
}

[BJOI2017]树的难题 点分治,线段树合并的更多相关文章

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

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

  2. P3714 [BJOI2017]树的难题 点分治+线段树合并

    题目描述 题目传送门 分析 路径问题考虑点分治 对于一个分治中心,我们可以很容易地得到从它开始的一条路径的价值和长度 问题就是如何将不同的路径合并 很显然,对于同一个子树中的所有路径,它们起始的颜色是 ...

  3. UVALive 7148 LRIP【树分治+线段树】

    题意就是要求一棵树上的最长不下降序列,同时不下降序列的最小值与最大值不超过D. 做法是树分治+线段树,假设树根是x,y是其当前需要处理的子树,对于子树y,需要处理出两个数组MN,MX,MN[i]表示以 ...

  4. BZOJ4012[HNOI2015]开店——树链剖分+可持久化线段树/动态点分治+vector

    题目描述 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到 人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱.这样的 想法当然非常好啦,但是她们也发现她们面临着一个 ...

  5. LOJ#6463 AK YOI 树分治+线段树合并

    传送门 既然是树上路径统计问题,不难想到要使用树分治,这里以点分治为例 由点分治的性质,每层只需要考虑经过重心的路径 因为需要维护路径长度在一定范围内的最大权值和,所以要用一个数据结构维护一下到根节点 ...

  6. 【loj6145】「2017 山东三轮集训 Day7」Easy 动态点分治+线段树

    题目描述 给你一棵 $n$ 个点的树,边有边权.$m$ 次询问,每次给出 $l$ .$r$ .$x$ ,求 $\text{Min}_{i=l}^r\text{dis}(i,x)$ . $n,m\le ...

  7. 【BZOJ4372】烁烁的游戏 动态树分治+线段树

    [BZOJ4372]烁烁的游戏 Description 背景:烁烁很喜欢爬树,这吓坏了树上的皮皮鼠.题意:给定一颗n个节点的树,边权均为1,初始树上没有皮皮鼠.烁烁他每次会跳到一个节点u,把周围与他距 ...

  8. 【bzoj4372】烁烁的游戏 动态点分治+线段树

    题目描述 给一颗n个节点的树,边权均为1,初始点权均为0,m次操作:Q x:询问x的点权.M x d w:将树上与节点x距离不超过d的节点的点权均加上w. 输入 第一行两个正整数:n,m接下来的n-1 ...

  9. 【bzoj3730】震波 动态点分治+线段树

    题目描述 在一片土地上有N个城市,通过N-1条无向边互相连接,形成一棵树的结构,相邻两个城市的距离为1,其中第i个城市的价值为value[i].不幸的是,这片土地常常发生地震,并且随着时代的发展,城市 ...

随机推荐

  1. js oc与线程

    分属不同的线程 //定义需要暴露给js的内容,这里我们只暴露personName和queryPersonName接口 @protocol PersonProtocol <JSExport> ...

  2. 【模板】Dijkstra总结

    Dijkstra算法使用于跑最短路的算法. 算法思想 假定图是不带负权的有向图或无向图,采用贪心策略,每次扩展一个距离为最短的点,在以这个点为中间点,更新其他的所有点的距离.当所有边权都为正时,由于不 ...

  3. Spring(十)之自定义事件

    编写自定义事件的简单流程如下: (1)编写CustomEvent.java package com.tutorialspoint; import org.springframework.context ...

  4. windows下搭建nginx+php开发环境

    windows下搭建nginx+php开发环境 1.前言 windows下大多我们都是下载使用集成环境,但是本地已经存在一个集成环境,但不适合项目的需求.因此准备再自己搭建一个环境. 2.准备 工具: ...

  5. (转)ci

    1  从代码管理器签出源文件 2  修改代码 3  编译代码 4  遇到错误,转到2继续修改直到达到预期 5  运行单元测试,期望所有的测试绿色(通过) 6  单元测试出错,转入2 7  重构代码,按 ...

  6. hibernate二级缓存实例

    hibernate.cfg.xml <?xml version='1.0' encoding='UTF-8'?><!DOCTYPE hibernate-configuration P ...

  7. 推荐一个配置linux服务的网站

    该网站的各种linux服务的配置都是基于CentOS系统的 基本上各种linux服务都有了 http://www.server-world.info/en/

  8. 【SP2713 GSS4 - Can you answer these queries IV】 题解

    题目链接:https://www.luogu.org/problemnew/show/SP2713 真暴力啊. 开方你开就是了,开上6次就都没了. #include <cmath> #in ...

  9. POJ 1182 食物链(经典带权并查集 向量思维模式 很重要)

    传送门: http://poj.org/problem?id=1182 食物链 Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: ...

  10. 404 Note Found 队 Alpha 6

    目录 组员情况 组员1(组长):胡绪佩 组员2:胡青元 组员3:庄卉 组员4:家灿 组员5:凯琳 组员6:翟丹丹 组员7:何家伟 组员8:政演 组员9:黄鸿杰 组员10:刘一好 组员11:何宇恒 展示 ...