[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. mongd配置文件解释

    mongd配置文件解释 系统日志配置 systemLog: verbosity: <int> quiet: <boolean> traceAllExceptions: < ...

  2. BZOJ1177:[APIO2009]Oil(枚举,前缀和)

    Description 采油区域 Siruseri政府决定将石油资源丰富的Navalur省的土地拍卖给私人承包商以建立油井.被拍卖的整块土地为一个矩形区域,被划分为M×N个小块. Siruseri地质 ...

  3. 【[HEOI2014]大工程 】

    可能是虚树板子题了 首先先把虚树建出来,但是这里和那道虚树的入门题不一样,这里所有的询问点都得在虚树里,所以不会存在那种直接不如栈的点 之后我们考虑一下这个三个要求的东西 第一个操作我们需要统计虚树上 ...

  4. 【[GDOI2014]拯救莫莉斯】

    可能我的状态比较鬼畜,应该没有人这么写 设\(dp[i][j][k]\)表示在第\(i\)行,放置油库的状态为\(j\),实际上周围已经有油库或者本身有油库的状态为\(k\)的时候的最小花费 由于我们 ...

  5. Kali-linux攻击路由器

    前面介绍的各种工具,都是通过直接破解密码,来连接到无线网络.由于在一个无线网络环境的所有设备中,路由器是最重要的设备之一.通常用户为了保护路由器的安全,通常会设置一个比较复杂的密码.甚至一些用户可能会 ...

  6. [Python 模块] logging模块、Logger类

    logging模块: 标准库里面的logging模块,在前面学习线程安全时曾用来解决print被打断的问题,这里会介绍logging模块的功能. logging模块是线程安全的,不需要客户做任何特殊的 ...

  7. 《Python核心编程》第二版第三章答案

    本人python新手,答案自己做的,如果有问题,欢迎大家评论和讨论! 更新会在本随笔中直接更新. 我在Windows使用python版本是2.7.0 3–10. 异常.使用类似readTextFile ...

  8. Luogu_4197 Peaks

    P4197 Peaks 并不会克鲁斯卡尔重构树,于是就写了离线算法. 使用了最小生成树,启发式合并treap 在最小生成树,克鲁斯卡尔算法 时 ,将询问一块处理.便可以保证询问时边的要求.然后利用平衡 ...

  9. 怎么用Python写爬虫抓取网页数据

    机器学习首先面临的一个问题就是准备数据,数据的来源大概有这么几种:公司积累数据,购买,交换,政府机构及企业公开的数据,通过爬虫从网上抓取.本篇介绍怎么写一个爬虫从网上抓取公开的数据. 很多语言都可以写 ...

  10. DBA手记-BBED 的说明

    在10g中连接生成bbed:cd $ORACLE_HOME/rdbms/libmake -f ins_rdbms.mk $ORACLE_HOME/rdbms/lib/bbed 11g中缺省未提供BBE ...