【BZOJ3995】[SDOI2015]道路修建 线段树区间合并

时间:2022-09-17 00:14:03

【BZOJ3995】[SDOI2015]道路修建

Description

 某国有2N个城市,这2N个城市构成了一个2行N列的方格网。现在该国*有一个旅游发展计划,这个计划需要选定L、R两列(L<=R),修建若干条专用道路,使得这两列之间(包括这两列)的所有2(R-L+1)个城市中每个城市可以只通过专用道路就可以到达这2(R-L+1)个城市中的任何一个城市。这种专用道路只能在同一行相邻两列的城市或者同一列的两个城市之间修建,且修建需要花费一定的费用。由于该国*决定尽量缩减开支,因此*决定,选定L、R后,只修建2(R-L+1)-1条专用道路,使得这些专用道路构成一个树结构。现在你需要帮助该国*写一个程序,完成这个任务。具体地,该任务包含M个操作,每个操作的格式如下:
1.        C x0 y0 x1 y1 w:由于重新对第x0行第y0列的城市和第x1行第y1列的城市之间的情况进行了考察,它们之间修建一条专用道路的花费变成了w;
2.        Q L R:若*选定的两列分别为L、R,询问*的最小开支。

Input

第一行,两个整数N、M。

第二行,N-1个整数,其中第i个整数表示初始时第1行第i列的城市和第1行第i+1列的城市之间修建一条专用道路的费用。
第三行,N-1个整数,其中第i个整数表示初始时第2行第i列的城市和第2行第i+1列的城市之间修建一条专用道路的费用。
第四行,N个整数,其中第i个整数表示初始时第1行第i列的城市和第2行第i列的城市之间修建一条专用道路的费用。
接下来的M行,每行一个操作。

Output

对于每个询问操作,输出一行,表示你计算出的*的最小开支。

Sample Input

3 3
1 2
2 1
3 1 2
Q 1 3
C 1 2 2 2 3
Q 2 3

Sample Output

7
5

HINT

对于全部的数据,1<=N, M<=60000,任何时刻任何一条专用道路的修建费用不超过10^4。

题解:第一次见到这题居然是在计蒜客上。。。一眼看出是线段树区间合并,但是真正写的时候。。。我被要维护的那一大坨东西征服了。于是去看了大爷的做法。

这里还是做一下大爷题解的注释吧:

先梳理出所有要维护的东西:区间端点,区间横边和,竖边个数,左侧(右)侧第一条竖边的值,左(右)侧竖边以及它左(右)侧的所有横边的最大值,MST的权值。

然后加入中间两条边,这样一定会形成环,找到环上最大的边mx。
如果这条边是左(右)侧的唯一一条竖边,则右(左)侧的最左(右)的竖边成为了区间中最左(右)侧的竖边,然后更新最大值。
否侧,直接更新最大值。

#include <cstdio>
#include <cstring>
#include <iostream>
#define lson x<<1
#define rson x<<1|1
using namespace std;
const int maxn=60010;
int v[maxn][3];
struct node
{
int l,r,lsm,rsm,lm,rm,hm,sum,cnt;
}s[maxn<<2];
int n,m;
char str[10];
inline int max(int a,int b,int c) {return max(a,max(b,c));}
inline int max(int a,int b,int c,int d) {return max(max(a,b),max(c,d));}
inline node merge(node x,node y)
{
node z;
z.l=x.l,z.r=y.r;
int mh=max(v[x.r][0],v[x.r][1]),mx=max(x.rm,y.lm,mh);
z.sum=x.sum+y.sum+v[x.r][0]+v[x.r][1]-mx,z.hm=max(x.hm,y.hm,mh),z.cnt=x.cnt+y.cnt;
if(mx==x.rsm&&x.cnt==1)
{
z.lsm=y.lsm,z.rsm=y.rsm,z.lm=max(x.hm,y.lm,mh),z.rm=y.rm,z.cnt--;
}
else if(mx==y.lsm&&y.cnt==1)
{
z.lsm=x.lsm,z.rsm=x.rsm,z.lm=x.lm,z.rm=max(x.rm,y.hm,mh),z.cnt--;
}
else
{
z.lsm=x.lsm,z.rsm=y.rsm,z.lm=x.lm,z.rm=y.rm,z.cnt-=(mx==x.rsm||mx==y.lsm);
}
return z;
}
inline void init(node &x)
{
x.lsm=x.rsm=x.lm=x.rm=x.sum=v[x.l][2],x.hm=0,x.cnt=1;
}
void build(int l,int r,int x)
{
if(l==r)
{
s[x].l=l,s[x].r=r,init(s[x]);
return ;
}
int mid=(l+r)>>1;
build(l,mid,lson),build(mid+1,r,rson);
s[x]=merge(s[lson],s[rson]);
}
void updata(int l,int r,int x,int a)
{
if(l==r)
{
init(s[x]);
return ;
}
int mid=(l+r)>>1;
if(a<=mid) updata(l,mid,lson,a);
else updata(mid+1,r,rson,a);
s[x]=merge(s[lson],s[rson]);
}
node query(int l,int r,int x,int a,int b)
{
if(a<=l&&r<=b) return s[x];
int mid=(l+r)>>1;
if(b<=mid) return query(l,mid,lson,a,b);
if(a>mid) return query(mid+1,r,rson,a,b);
return merge(query(l,mid,lson,a,b),query(mid+1,r,rson,a,b));
}
inline int rd()
{
int ret=0,f=1; char gc=getchar();
while(gc<'0'||gc>'9') {if(gc=='-')f=-f; gc=getchar();}
while(gc>='0'&&gc<='9') ret=ret*10+gc-'0',gc=getchar();
return ret*f;
}
int main()
{
n=rd(),m=rd();
int i,a,b,c,d;
for(i=1;i<n;i++) v[i][0]=rd();
for(i=1;i<n;i++) v[i][1]=rd();
for(i=1;i<=n;i++) v[i][2]=rd();
build(1,n,1);
for(i=1;i<=m;i++)
{
scanf("%s",str);
if(str[0]=='C')
{
a=rd(),b=rd(),c=rd(),d=rd();
if(a!=c) v[b][2]=rd(),updata(1,n,1,b);
else
{
if(b>d) swap(b,d);
if(a==1) v[b][0]=rd();
else v[b][1]=rd();
updata(1,n,1,b);
}
}
else a=rd(),b=rd(),printf("%d\n",query(1,n,1,a,b).sum);
}
return 0;
}//3 3 1 2 2 1 3 1 2 Q 1 3 C 1 2 2 2 3 Q 2 3

【BZOJ3995】[SDOI2015]道路修建 线段树区间合并的更多相关文章

  1. &lbrack;bzoj3995&rsqb; &lbrack;SDOI2015&rsqb;道路修建 线段树

    Description 某国有2N个城市,这2N个城市构成了一个2行N列的方格网.现在该国*有一个旅游发展计划,这个计划需要选定L.R两列(L<=R),修建若干条专用道路,使得这两列之间(包括 ...

  2. &lbrack;SDOI2015&rsqb;道路修建&lpar;线段树&rpar;

    题意:给定2行n列的四连通带权网格图,支持修改边权和查询第[l,r]列的最小生成树 题解:这是一道好题,要么SDOI2019中n=2的20pts怎么会“我抄我自己”?(当然NOIP2018“我抄我自己 ...

  3. 【bzoj1018】&lbrack;SHOI2008&rsqb;堵塞的交通traffic 线段树区间合并&plus;STL-set

    题目描述 给出一张2*n的网格图,初始每条边都是不连通的.多次改变一条边的连通性或询问两个点是否连通. 输入 第一行只有一个整数C,表示网格的列数.接下来若干行,每行为一条交通信息,以单独的一行“Ex ...

  4. POJ 3667 Hotel&lpar;线段树 区间合并&rpar;

    Hotel 转载自:http://www.cnblogs.com/scau20110726/archive/2013/05/07/3065418.html [题目链接]Hotel [题目类型]线段树 ...

  5. HDU 3911 线段树区间合并、异或取反操作

    题目:http://acm.hdu.edu.cn/showproblem.php?pid=3911 线段树区间合并的题目,解释一下代码中声明数组的作用: m1是区间内连续1的最长长度,m0是区间内连续 ...

  6. HDU 3911 Black And White(线段树区间合并&plus;lazy操作)

    开始以为是水题,结果...... 给你一些只有两种颜色的石头,0为白色,1为黑色. 然后两个操作: 1 l r 将[ l , r ]内的颜色取反 0 l r 计算[ l , r ]内最长连续黑色石头的 ...

  7. HYSBZ 1858 线段树 区间合并

    //Accepted 14560 KB 1532 ms //线段树 区间合并 /* 0 a b 把[a, b]区间内的所有数全变成0 1 a b 把[a, b]区间内的所有数全变成1 2 a b 把[ ...

  8. poj3667 线段树 区间合并

    //Accepted 3728 KB 1079 ms //线段树 区间合并 #include <cstdio> #include <cstring> #include < ...

  9. hdu3911 线段树 区间合并

    //Accepted 3911 750MS 9872K //线段树 区间合并 #include <cstdio> #include <cstring> #include &lt ...

随机推荐

  1. HBase 建表新增数据记录

    login as: root root@192.168.12.23's password: ********* Last login: Wed Aug 20 00:41:17 2014 from 19 ...

  2. ECOS-Ecstore 后台管理地址修改

    ECStore默认出厂的后台管理地址是: http://域名/index.php/shopadmin http://域名/shopadmin [配置过rewrite后,并开启伪静态] 如果想要更个性的 ...

  3. 赵雅智:service与訪问者之间进行通信,数据交换

    服务类 中间人:service服务中的bind对象 创建中间人并通过onBinder方法的return暴露出去 watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQ ...

  4. jmeter使用TCP请求时,乱码问题,字符集设置

    不墨迹,直接上干货.(提示:UTF-8一个汉字占3个字节) TCP请求默认发的是GBK字符集,要想修改成UTF-8,只需要修改bin目录下的jmeter.properties文件,其中tcp.char ...

  5. 1、redis 基础

    1.1 导言 如果你从来没使用过 Redis 数据库,那你肯定会问,为什么我们要学 Redis数据库,我只使用 MySQL 或 Oracle 就够了.其实 Redis 虽叫数据库,可又不是传统意义上的 ...

  6. JUnit-三角形判断测试

    添加工具 1.添加JUnit测试工具: 使用eclipse自带的JUnit或者下载相关包.使用方式如下: 新建一个项目后,点击next出现以下界面: 选择添加JUnit 选择完成出现以下目录文件: p ...

  7. drawCall&lowbar;01

    在屏幕上渲染物体,引擎需要发出一个绘制调用来访问图形API(iOS系统中为OpenGL ES).每个绘制调用需要进行大量的工作来访问图形API,从而导致了CPU方面显著的性能开销.   Unity在运 ...

  8. js&lowbar;时间戳和时间格式之间的转换。

    关于我的理解,简单明了点: 时间戳:把一个日期使用一个数字表示出来,这个数字就是这个日期的秒数. 日期:就是我们常见的时间表现形式. 时间戳对于一般看时间不够直观明了,可是在程序的世界里作用可大了. ...

  9. CodeWarrior的map文件详解

    前言 map文件保存了你的整个程序编译链接后的各种信息,包括编译器链接器信息,内存分配信息,对象依赖等,每次编译链接程序后,这个文件都会被覆盖重新生成. 对我来说,它最主要的作用是它详尽的描述了整个程 ...

  10. Java中的Validated验证

    注意点:在使用@NotBlank时,必须与@Valid配着使用,不然不起作用(出现了很奇怪的现象,我第一次试的时候确实有这情况,但是第二次的时候这情况没了,所以这个说不准) @NotBlank 用在S ...