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。

Source

Round 1 感谢yts1999上传

Solution

这题就是一个\(2*n\)的网格图,求区间最小生成树,支持单边修改。

我会kruskal!然而并没有什么用

考虑这样的图的最小生成树长什么样,以及是否存在可合并性。

显而易见的是一定至少有一条竖边。

再接着分析,如果要合并两个相邻但不连通的最小生成树,我们有一个非常好的办法:

先连接上下两条边,这时候一定能够形成一个矩形形状的环,我们在这个环中找到最大的元素,并且删去,这样就完成了相邻的最小生成树的合并。

所以我们用线段树的话,每个节点需要维护的信息如下:

左右端点,最左最右竖边的权值,以及最左最右竖边向左(右)延伸到尽头的边最大值(类似一个三面半包围结构),所有横边的最大值,答案,竖边的个数。

合并的时候,左右端点,所有横边的最大值,答案,竖边个数可以直接求出。但是有需要特判的地方:

如果某一边的竖边只有一个,那么新的左右竖边权值,左右竖边左右延伸最大值都要根据情况去变化。

千万要写else!!不然两边权值相等并且两边各只有一个竖边的话会发生奇怪的错误。

其实代码并不难写只是细节有点多

Code

#include <bits/stdc++.h>
using namespace std;
#define N 60005
#define mid ((l+r)>>1)
int a,b,c,d,e,n,m,v[N][3];char o[5];
struct nod{int l,r,lm,rm,ls,rs,am,ans,cnt;void init(int x){lm=rm=ls=rs=ans=v[x][2];cnt=1;am=0;}}s[N*4];
nod merge(nod x,nod y)
{
nod z;z.l=x.l;z.r=y.r;
int mxh=max(v[x.r][0],v[x.r][1]),mx=max(max(x.rm,y.lm),mxh);
z.ans=x.ans+y.ans+v[x.r][0]+v[x.r][1]-mx;z.am=max(max(x.am,y.am),mxh);z.cnt=x.cnt+y.cnt;
if(mx==x.rs&&x.cnt==1) z.lm=max(x.am,max(y.lm,mxh)),z.rm=y.rm,z.ls=y.ls,z.rs=y.rs,z.cnt--;
else if(mx==y.ls&&y.cnt==1) z.lm=x.lm,z.rm=max(y.am,max(mxh,x.rm)),z.ls=x.ls,z.rs=x.rs,z.cnt--;
else z.lm=x.lm,z.rm=y.rm,z.ls=x.ls,z.rs=y.rs,z.cnt-=(mx==x.rs||mx==y.ls);
return z;
}
void bud(int x,int l,int r)
{
if(l==r){s[x].init(l);s[x].l=l;s[x].r=r;return;}
bud(x*2,l,mid);bud(x*2+1,mid+1,r);s[x]=merge(s[x*2],s[x*2+1]);
}
void upd(int x,int l,int r,int p)
{
if(l==r){s[x].init(l);return;}
if(p<=mid) upd(x*2,l,mid,p);else upd(x*2+1,mid+1,r,p);s[x]=merge(s[x*2],s[x*2+1]);
}
nod que(int x,int l,int r,int b,int e)
{
if(b<=l&&r<=e) return s[x];
if(e<=mid) return que(x*2,l,mid,b,e);if(b>mid) return que(x*2+1,mid+1,r,b,e);
return merge(que(x*2,l,mid,b,e),que(x*2+1,mid+1,r,b,e));
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<n;i++) scanf("%d",&v[i][0]);
for(int i=1;i<n;i++) scanf("%d",&v[i][1]);
for(int i=1;i<=n;i++) scanf("%d",&v[i][2]);
bud(1,1,n);
for(int i=1;i<=m;i++)
{
scanf("%s",o);
if(o[0]=='Q') scanf("%d%d",&a,&b),printf("%d\n",que(1,1,n,a,b).ans);
else
{
scanf("%d%d%d%d%d",&a,&b,&c,&d,&e);if(b>d) swap(b,d);
if(a!=c) v[b][2]=e,upd(1,1,n,b);else v[b][a-1]=e,upd(1,1,n,b);
}
}
}

[bzoj3995] [SDOI2015]道路修建 线段树的更多相关文章

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

    [BZOJ3995][SDOI2015]道路修建 Description  某国有2N个城市,这2N个城市构成了一个2行N列的方格网.现在该国政府有一个旅游发展计划,这个计划需要选定L.R两列(L&l ...

  2. [SDOI2015]道路修建(线段树)

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

  3. 【线段树】bzoj3995 [SDOI2015]道路修建

    线段树每个结点维护5个域: 整个区间的MST. 将两个左端点连通,两个右端点不连通,整个区间内选择2*(r-l+1)-2条边的最小生成森林,有两个连通块. 将两个右端点连通,两个左端点不连通,整个区间 ...

  4. bzoj3995[SDOI2015]道路修建

    http://www.lydsy.com/JudgeOnline/problem.php?id=3995 线段树维护连通性. 我们发现,对于一个区间[L,R],我们只需要知道(1,L),(2,L),( ...

  5. [BZOJ 3995] [SDOI2015] 道路修建 【线段树维护连通性】

    题目链接:BZOJ - 3995 题目分析 这道题..是我悲伤的回忆.. 线段树维护连通性,与 BZOJ-1018 类似,然而我省选之前并没有做过  1018,即使它在 ProblemSet 的第一页 ...

  6. 洛谷P2505||bzoj2750 [HAOI2012]道路 && zkw线段树

    https://www.luogu.org/problemnew/show/P2505 https://www.lydsy.com/JudgeOnline/problem.php?id=2750 神奇 ...

  7. LOJ #2831. 「JOISC 2018 Day 1」道路建设 线段树+Link-cut-tree

    用 LCT 维护颜色相同连通块,然后在线段树上查一下逆序对个数就可以了. code: #include <cstdio> #include <algorithm> #inclu ...

  8. BZOJ 2435:[Noi2011]道路修建(树型DP)

    http://www.lydsy.com/JudgeOnline/problem.php?id=2435 题意:中文题意. 思路:很简单的树形DP,sz记录儿子有多少个和cur记录走的哪条弧,然后直接 ...

  9. 【XSY2528】道路建设 LCT 可持久化线段树

    题目描述 给你一个\(n\)个点\(m\)条边图,\(q\)个询问,每次问你边权在\([l,r]\)之间的边组成的最小生成树(森林)的边权和.强制在线. \(n,m,q\leq 100000\) 题解 ...

随机推荐

  1. 跨域资源共享/option 请求产生原因

    https://blog.csdn.net/hfahe/article/details/7730944

  2. 【转】mac os、linux及unix之间的关系

    mac os.linux及unix之间的关系   unix 是由贝尔实验室开发的多用户.多任务操作系统 linux是一类Unix操作系统的统称,严格来说,linux系统只有内核叫“linux”,而li ...

  3. LPCTSTR和LPTSTR和char *究竟有什么区别

    LPSTR = char* LPCSTR = const char* LPTSTR: 如果定义了UNICODE宏,那么LPTSTR = wchar_t*否则LPTSTR = char* LPCTSTR ...

  4. thrift框架

    thrift是一个软件框架,用来进行可扩展且跨语言的服务的开发.它结合了功能强大的软件堆栈和代码生成引擎,以构建在 C++, Java, Python, PHP, Ruby, Erlang, Perl ...

  5. 第七章 二叉搜索树 07B2-1 插入:算法

  6. Chrome 扩展 Vue Devtools

    Vue.js devtools是基于google chrome浏览器的一款调试vue.js应用的开发者浏览器扩展,可以在浏览器开发者工具下调试代码. 1)首先在github下载devtools源码,地 ...

  7. BUILDING ANGULAR APPS USING FLUX ARCHITECTURE

    Flux is an architectural pattern based on unidirectional data flow. Although it is originated in the ...

  8. 我的border能自定义四角之border-radius : 左上角,右上角,左下角,右下角。

    1 边框:border: 1px solid #0081df; 2 想要单独加上四个圆角: border-bottom-left-radius: 5px; border-top-left-radius ...

  9. linux 查找php.ini在那个文件夹

    第一种方法:通过phpinfo查看 第二种方法: 执行 php -i | grep php.ini 结果如下:

  10. C# Http请求接口数据的两种方式Get and Post

    面向接口编程是一种设计思想,无论用什么语言都少不了面向接口开发思想,在软件开发过程中,常常要调用接口,接下来就是介绍C#调用其它开发商提供的接口进行获取数据,http接口方式获取接口数据. Get请求 ...