博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
SDOI2015 道路修建
阅读量:6072 次
发布时间:2019-06-20

本文共 3520 字,大约阅读时间需要 11 分钟。

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
 

Data Constraint

对于40%的数据,1<=N, M<=600;
对于全部的数据,1<=N, M<=60000,任何时刻任何一条专用道路的修建费用不超过104。
 

解法:用线段树维护区间内的MST

具体合并方法如下:

首先,由于两个都是树结构,我们把区间间的两条边连起来,会出现一个环,我们只需要把环上最长的边cut掉即可

 

\

首先,绿色部分可以O(1)计算,我们需要维护的只是红色和蓝色部分,即区间内最左和最右的竖边,以及其左/右横边的Max .

如果我们cut的是是横边,或者虽然cut了竖边但区间内有多条竖边(cut蓝色边),那么大区间的lc(最左竖边再左边横框的Max,即蓝色部分),rc(红色部分)都可以直接用两个小区间的lc,rc更新。

但是如果我们cut的竖边是区间内唯一的竖边,如红色边,那么我们新区间的lc需用蓝,绿,以及左边横边的Max更新,由于左边区间只有一条竖边,那么该区间的lc,rc即囊括了所有横边,直接用其来更新即可

右边同理。

 

End.

 

#include
#include
#include
#include
#include
using namespace std;struct Tree{ int lef,rig,sum,lc,rc,dn;}tr[300011];int A[60011],B[60011],c[60011];int n,m,i,sx,sy,tx,ty,w,ans,l,r;Tree Tr;char s[11];Tree Merge(Tree a,Tree b,int r){ bool pw,cut; int kd,mx; Tree c; mx=0; mx=max(a.rig,mx);mx=max(b.lef,mx); mx=max(a.rc,mx);mx=max(b.lc,mx); mx=max(A[r],mx);mx=max(B[r],mx); pw=false; cut=false; if(mx==a.rig){ if(a.dn==1){ pw=true; kd=1; } cut=true; } if(mx==b.lef){ if(b.dn==1){ pw=true; kd=2; } cut=true; } c.dn=a.dn+b.dn; if(cut)c.dn--; c.sum=a.sum+b.sum+A[r]+B[r]-mx; if(pw==false){ c.lc=a.lc;c.rc=b.rc; c.lef=a.lef;c.rig=b.rig; } else if(kd==1){ c.rc=b.rc;c.rig=b.rig; c.lc=b.lc;c.lc=max(c.lc,a.rc);c.lc=max(c.lc,a.lc); c.lc=max(c.lc,A[r]);c.lc=max(c.lc,B[r]); c.lef=b.lef; } else{ c.lc=a.lc;c.lef=a.lef; c.rc=a.rc;c.rc=max(c.rc,b.lc);c.rc=max(c.rc,b.rc); c.rc=max(c.rc,A[r]);c.rc=max(c.rc,B[r]); c.rig=a.rig; } return c;}void build(int l,int r,int t){ if(l==r){ tr[t].lc=tr[t].rc=0; tr[t].lef=tr[t].rig=c[l]; tr[t].dn=1; tr[t].sum=c[l]; return; } int mid; mid=(l+r)/2; build(l,mid,t+t); build(mid+1,r,t+t+1); tr[t]=Merge(tr[t+t],tr[t+t+1],mid);}void insert(int t,int l,int r,int x){ if(l==r){ tr[t].lef=tr[t].rig=c[l]; tr[t].sum=c[l]; return; } int mid; mid=(l+r)/2; if(x<=mid)insert(t+t,l,mid,x); if(x>mid)insert(t+t+1,mid+1,r,x); tr[t]=Merge(tr[t+t],tr[t+t+1],mid);}Tree ask(int t,int l,int r,int x,int y){ int mid; if(l==x&&r==y)return tr[t]; mid=(l+r)/2; if(y<=mid)return ask(t+t,l,mid,x,y); if(x>mid)return ask(t+t+1,mid+1,r,x,y); if(x<=mid&&y>mid)return Merge(ask(t+t,l,mid,x,mid),ask(t+t+1,mid+1,r,mid+1,y),mid);}int main(){ scanf("%d%d",&n,&m); for(i=1;i
ty)swap(sy,ty); if(sx==1)A[sy]=w; else B[sy]=w; } insert(1,1,n,sy); } else{ scanf("%d%d",&l,&r); Tr=ask(1,1,n,l,r); ans=Tr.sum; printf("%d\n",ans); } }}

 

转载于:https://www.cnblogs.com/applejxt/p/4445654.html

你可能感兴趣的文章
「翻译」逐步替换Sass
查看>>
H5实现全屏与F11全屏
查看>>
处理excel表的列
查看>>
枸杞子也能控制脂肪肝
查看>>
Excuse me?这个前端面试在搞事!
查看>>
C#数据采集类
查看>>
quicksort
查看>>
检验函数运行时间
查看>>
【BZOJ2019】nim
查看>>
Oracle临时表空间满了的解决办法
查看>>
四部曲
查看>>
LINUX内核调试过程
查看>>
【HDOJ】3553 Just a String
查看>>
Java 集合深入理解(7):ArrayList
查看>>
2019年春季学期第四周作业
查看>>
linux环境配置
查看>>
ASP.NET MVC中从前台页面视图(View)传递数据到后台控制器(Controller)方式
查看>>
lintcode:next permutation下一个排列
查看>>
python 递归
查看>>
一个想法(续二):换个角度思考如何解决IT企业招聘难的问题!
查看>>