[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。
Source
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]道路修建 线段树的更多相关文章
- 【BZOJ3995】[SDOI2015]道路修建 线段树区间合并
[BZOJ3995][SDOI2015]道路修建 Description 某国有2N个城市,这2N个城市构成了一个2行N列的方格网.现在该国政府有一个旅游发展计划,这个计划需要选定L.R两列(L&l ...
- [SDOI2015]道路修建(线段树)
题意:给定2行n列的四连通带权网格图,支持修改边权和查询第[l,r]列的最小生成树 题解:这是一道好题,要么SDOI2019中n=2的20pts怎么会“我抄我自己”?(当然NOIP2018“我抄我自己 ...
- 【线段树】bzoj3995 [SDOI2015]道路修建
线段树每个结点维护5个域: 整个区间的MST. 将两个左端点连通,两个右端点不连通,整个区间内选择2*(r-l+1)-2条边的最小生成森林,有两个连通块. 将两个右端点连通,两个左端点不连通,整个区间 ...
- bzoj3995[SDOI2015]道路修建
http://www.lydsy.com/JudgeOnline/problem.php?id=3995 线段树维护连通性. 我们发现,对于一个区间[L,R],我们只需要知道(1,L),(2,L),( ...
- [BZOJ 3995] [SDOI2015] 道路修建 【线段树维护连通性】
题目链接:BZOJ - 3995 题目分析 这道题..是我悲伤的回忆.. 线段树维护连通性,与 BZOJ-1018 类似,然而我省选之前并没有做过 1018,即使它在 ProblemSet 的第一页 ...
- 洛谷P2505||bzoj2750 [HAOI2012]道路 && zkw线段树
https://www.luogu.org/problemnew/show/P2505 https://www.lydsy.com/JudgeOnline/problem.php?id=2750 神奇 ...
- LOJ #2831. 「JOISC 2018 Day 1」道路建设 线段树+Link-cut-tree
用 LCT 维护颜色相同连通块,然后在线段树上查一下逆序对个数就可以了. code: #include <cstdio> #include <algorithm> #inclu ...
- BZOJ 2435:[Noi2011]道路修建(树型DP)
http://www.lydsy.com/JudgeOnline/problem.php?id=2435 题意:中文题意. 思路:很简单的树形DP,sz记录儿子有多少个和cur记录走的哪条弧,然后直接 ...
- 【XSY2528】道路建设 LCT 可持久化线段树
题目描述 给你一个\(n\)个点\(m\)条边图,\(q\)个询问,每次问你边权在\([l,r]\)之间的边组成的最小生成树(森林)的边权和.强制在线. \(n,m,q\leq 100000\) 题解 ...
随机推荐
- Direcshow相关资料
CCapture directshow 视频捕获类: http://blog.csdn.net/xgx198831/article/details/7284618 ICaptureGraphBuild ...
- 从LinqPad入门Linq
为什么要学习Linq? 在我们日常开发中,经常需要从数据库中执行各式各样的查询来获取需要的数据.但是如果需要对查询获得的数据进行二次筛选呢?linq就提供了对于可枚举类型(实现IEnumerable接 ...
- 取消Eclipse的Error Reporting
选择Preferences->General->Error Reporting,Send Mode选择Never send reports
- spring mvc请求参数中文乱码解决方案
POST 请求 在web.xml中加上增加过滤器 <filter> <filter-name>encodingFilter</filter-name> <fi ...
- 什么是First-class citizen?
[什么是First-class citizen?] In programming language design, a first-class citizen (also type, object, ...
- java链接数据库构建sql语句的时候容易记混的地方
Connection conn = DBHelper.getconnection(); //封装连接数据库的工具类 String sql = "select * from t_test&qu ...
- freemaker在表格中遍历数据
Controller层如下所示: @RequestMapping(value = "/test", method = RequestMethod.GET) public Strin ...
- ICG游戏:斐波那契博弈
描述: 有一堆个数为n(n>=2)的石子,游戏双方轮流取石子,规则如下: 1)先手不能在第一次把所有的石子取完,至少取1颗: 2)之后每次可以取的石子数至少为1,至多为对手刚取的石子数的2倍: ...
- Linux 启动和关闭自定义命令
首先是启动命令 [lambert@lambert ~]$ vim startup.sh #!/bin/bash nohup XXXXXX >/home/lambert/>& &am ...
- COGS 2189 帕秋莉的超级多项式
放模板啦! 以后打比赛的时候直接复制过来. 说句实话vector的效率真的不怎么样,但是似乎也还行,最主要是……写得比较爽. #include <cstdio> #include < ...