【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,考虑合并区间[l,mid],[mid,r] ,线段树每个节点维护该区间的mst最左边的竖线位置,最右边的竖线位置,横线的最大值,左端点到最左边竖线中横线最大值,右端点到最右边竖线中横线的最大值,还有答案,合并的时候瞎讨论一下去掉那条边即可即可。

还有一个代码写的不错,思路差不多的博客点击打开链接

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
const int N=60010;
const int MAX=60010*10-5;
struct tree{
    int l,r,lmx,rmx,mx,ans;
}t[N*10];
int n,m,c[N],v[N][3];
inline void update(int x,int x1,int x2){
    t[x].mx=max(t[x1].mx,t[x2].mx);
    t[x].ans=t[x1].ans+t[x2].ans;
    t[x].l=t[x1].l;t[x].lmx=t[x1].lmx;
    t[x].r=t[x2].r;t[x].rmx=t[x2].rmx;
    int mx=max(t[x1].rmx,t[x2].lmx); 
    if(t[x1].r==t[x2].l) t[x].ans-=c[t[x1].r];
    else if(mx>=max(c[t[x1].r],c[t[x2].l])) t[x].ans-=mx;
    else if(c[t[x1].r]>c[t[x2].l]){
        t[x].ans-=c[t[x1].r];
        if(t[x1].l==t[x1].r) t[x].l=t[x2].l,t[x].lmx=max(t[x1].mx,t[x2].lmx);
    }
    else {
        t[x].ans-=c[t[x2].l];
        if(t[x2].l==t[x2].r) t[x].r=t[x1].r,t[x].rmx=max(t[x2].mx,t[x1].rmx);
    }
    return ;
}
inline void build(int x,int l,int r){
    if(l+1==r){
        t[x].mx=max(v[l][0],v[l][1]);
        if(t[x].mx>=max(c[l],c[r])){
            t[x].ans=c[l]+c[r]+v[l][0]+v[l][1]-t[x].mx;t[x].l=l;t[x].r=r;t[x].lmx=t[x].rmx=0;
        }
        else if(c[l]>c[r]){
            t[x].ans=v[l][0]+v[l][1]+c[r];t[x].l=t[x].r=r;t[x].lmx=t[x].mx;t[x].rmx=0;
        }
        else {
            t[x].ans=v[l][0]+v[l][1]+c[l];t[x].r=t[x].l=l;t[x].lmx=0;t[x].rmx=t[x].mx;
        }
        return ;
    }
    int mid=(l+r)>>1;
    build(x*2,l,mid);
    build(x*2+1,mid,r);
    update(x,x*2,x*2+1); 
}
inline void change(int x,int l,int r,int x1,int y1){
    if(x1>y1) return ;
    if(l+1==r){
        t[x].mx=max(v[l][0],v[l][1]);
        if(t[x].mx>=max(c[l],c[r])){
            t[x].ans=c[l]+c[r]+v[l][0]+v[l][1]-t[x].mx;t[x].l=l;t[x].r=r;t[x].lmx=t[x].rmx=0;
        }
        else if(c[l]>c[r]){
            t[x].ans=v[l][0]+v[l][1]+c[r];t[x].l=t[x].r=r;t[x].lmx=t[x].mx;t[x].rmx=0;
        }
        else {
            t[x].ans=v[l][0]+v[l][1]+c[l];t[x].r=t[x].l=l;t[x].lmx=0;t[x].rmx=t[x].mx;
        }
        return ;
    }
    int mid=(l+r)>>1;
    change(x*2,l,mid,x1,min(y1,mid));
    change(x*2+1,mid,r,max(mid,x1),y1);
    update(x,x*2,x*2+1);
}
tree query(int x,int l,int r,int x1,int y1){
    if(x1==l&&y1==r) return t[x];
    int mid=(l+r)>>1;
    if(y1<=mid) return query(x*2,l,mid,x1,y1);
    else if(x1>=mid) return query(x*2+1,mid,r,x1,y1);
    else {
         tree u=query(x*2,l,mid,x1,mid),v=query(x*2+1,mid,r,mid,y1);
         t[MAX-2]=u,t[MAX-1]=v;
         update(MAX,MAX-2,MAX-1);
         return t[MAX];
    }
}
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",&c[i]);
    build(1,1,n);
    for(int i=1;i<=m;i++){
        char o[3];int l,r,x1,x2,y1,y2,w;
        scanf("%s",o);
        if(o[0]=='Q'){
            scanf("%d%d",&l,&r);
            if(l==r) {
                printf("%d\n",c[l]);
            }
            else {
                tree u=query(1,1,n,l,r);
                printf("%d\n",u.ans);
            } 
        }
        else {
            scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&w);
            if(x1>x2) swap(x1,x2);
            if(y1>y2) swap(y1,y2);
            if(x1==x2) v[y1][x1-1]=w;
            else c[y2]=w;
            change(1,1,n,y1,y2);
        }
    }
    return 0;
}

    原文作者:道路修建问题
    原文地址: https://blog.csdn.net/dcx2001/article/details/78167989
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞