zoukankan      html  css  js  c++  java
  • 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
     

    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<cstdio>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    #include<cstring>
    
    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<n;i++)scanf("%d",&A[i]);
        for(i=1;i<n;i++)scanf("%d",&B[i]);
        for(i=1;i<=n;i++)scanf("%d",&c[i]);
        build(1,n,1);
        for(i=1;i<=m;i++){
            scanf("%s",&s);
            if(s[0]=='C'){
                scanf("%d%d%d%d%d",&sx,&sy,&tx,&ty,&w);
                if(sy==ty)c[sy]=w;
                else{
                    if(sy>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
    ",ans);
            }
        }
    }
  • 相关阅读:
    Ubuntu18.04 修改DNS
    windows系统如何通过Xshell 客户端连接 linux系统(主要介绍ubuntu系统)
    如何获取 docker 容器(container)的 ip 地址(转)
    基于Docker搭建LNMP环境(转)
    高并发处理【电商抢购】(转)
    [golang] Glide 包管理
    如何查看2to3.PY的帮助文档
    python模块之lib2to3(py2转py3自动化工具)
    python模块之keyword
    python模块之JSON
  • 原文地址:https://www.cnblogs.com/applejxt/p/4445654.html
Copyright © 2011-2022 走看看