3995: [SDOI2015]道路修建

3995: [SDOI2015]道路修建

Time Limit: 30 Sec  
Memory Limit: 128 MB

Submit: 271  
Solved: 142

[
Submit][
Status][
Discuss]

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上传

[
Submit][
Status][
Discuss]



做这题之前建议先做bzoj1018,(大概算是弱化版?),反正思路要从那题借鉴

考虑通过线段树维护保持某个区间某种连通性的最小代价

说是某种,就是分类讨论这个区间内四个角构成不同形态连通块的情形

大致可以简易分成以下五大类《3995: [SDOI2015]道路修建》

这样,一次询问对应到线段树上O(logn)个区间

把这些节点拿出来,讨论合并一下就行了

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
 
const int maxn = 6E4 + 60;
const int T = 4;
const int INF = 1E9 + 233;
 
struct Node{
    int a[5]; Node(){for (int i = 0; i < 5; i++) a[i] = INF;}
}c[maxn*T],stk[maxn],Ans;
int n,m,tp,E[2][maxn][3],Left[maxn];
 
Node Merge(Node L,Node R,int S,int M)
{
    Node ret;
    ret.a[0] = min(ret.a[0],L.a[0] + R.a[0] + M);
    ret.a[0] = min(ret.a[0],L.a[0] + R.a[1] + S);
    ret.a[2] = min(ret.a[2],L.a[0] + R.a[2] + M);
    ret.a[0] = min(ret.a[0],L.a[0] + R.a[3] + S);
    ret.a[2] = min(ret.a[2],L.a[0] + R.a[3] + M);
    ret.a[2] = min(ret.a[2],L.a[0] + R.a[4] + S);
     
    ret.a[1] = min(ret.a[1],L.a[1] + R.a[0] + M);
    ret.a[1] = min(ret.a[1],L.a[1] + R.a[1] + S);
    ret.a[4] = min(ret.a[4],L.a[1] + R.a[2] + M);
    ret.a[1] = min(ret.a[1],L.a[1] + R.a[3] + S);
    ret.a[4] = min(ret.a[4],L.a[1] + R.a[3] + M);
    ret.a[4] = min(ret.a[4],L.a[1] + R.a[4] + S);
     
    ret.a[0] = min(ret.a[0],L.a[2] + R.a[0] + S);
    ret.a[2] = min(ret.a[2],L.a[2] + R.a[2] + S);
    ret.a[2] = min(ret.a[2],L.a[2] + R.a[3] + S);
     
    ret.a[0] = min(ret.a[0],L.a[3] + R.a[0] + S);
    ret.a[1] = min(ret.a[1],L.a[3] + R.a[0] + M);
    ret.a[1] = min(ret.a[1],L.a[3] + R.a[1] + S);
    ret.a[4] = min(ret.a[4],L.a[3] + R.a[2] + M);
    ret.a[2] = min(ret.a[2],L.a[3] + R.a[2] + S);
    ret.a[4] = min(ret.a[4],L.a[3] + R.a[3] + M);
    ret.a[3] = min(ret.a[3],L.a[3] + R.a[3] + S);
    ret.a[4] = min(ret.a[4],L.a[3] + R.a[4] + S);
     
    ret.a[1] = min(ret.a[1],L.a[4] + R.a[0] + S);
    ret.a[4] = min(ret.a[4],L.a[4] + R.a[2] + S);
    ret.a[4] = min(ret.a[4],L.a[4] + R.a[3] + S);
    return ret;
}
 
void Build(int o,int l,int r)
{
    if (l == r)
    {
        c[o].a[0] = E[0][l][2];
        c[o].a[3] = 0; return;
    }
    int mid = l + r >> 1,U,D;
    Build(o<<1,l,mid); Build(o<<1|1,mid+1,r);
    U = E[0][mid][1],D = E[1][mid][1];
    c[o] = Merge(c[o<<1],c[o<<1|1],U + D,min(U,D));
}
 
void Modify(int o,int l,int r,int ql,int qr)
{
    if (l == r) {c[o].a[0] = E[0][l][2]; return;}
    int mid = l + r >> 1,U,D;
    if (ql <= mid) Modify(o<<1,l,mid,ql,qr);
    if (qr > mid) Modify(o<<1|1,mid+1,r,ql,qr);
    U = E[0][mid][1],D = E[1][mid][1];
    c[o] = Merge(c[o<<1],c[o<<1|1],U + D,min(U,D));
}
 
void GetRange(int o,int l,int r,int ql,int qr)
{
    if (ql <= l && r <= qr)
    {
        stk[++tp] = c[o];
        Left[tp] = l; return;
    }
    int mid = l + r >> 1;
    if (ql <= mid) GetRange(o<<1,l,mid,ql,qr);
    if (qr > mid) GetRange(o<<1|1,mid+1,r,ql,qr);
}
 
int getint()
{
    char ch = getchar(); int ret = 0;
    while (ch < '0' || '9' < ch) ch = getchar();
    while ('0' <= ch && ch <= '9')
        ret = ret * 10 + ch - '0',ch = getchar();
    return ret;
}
 
int getcom()
{
    char ch = getchar();
    while (ch != 'C' && ch != 'Q') ch = getchar();
    return ch == 'C' ? 1 : 2;
}
 
int main()
{
    #ifdef DMC
        freopen("DMC.txt","r",stdin);
    #endif
     
    n = getint(); m = getint();
    for (int i = 1; i < n; i++)
        E[0][i][1] = E[0][i + 1][0] = getint();
    for (int i = 1; i < n; i++)
        E[1][i][1] = E[1][i + 1][0] = getint();
    for (int i = 1; i <= n; i++)
        E[0][i][2] = E[1][i][2] = getint();
    Build(1,1,n);
    while (m--)
    {
        int com = getcom();
        if (com == 1)
        {
            int r1,c1,r2,c2,w;
            r1 = getint(); c1 = getint();
            r2 = getint(); c2 = getint();
            --r1; --r2; w = getint();
            if (c1 != c2)
            {
                if (c1 > c2) swap(c1,c2);
                E[r1][c1][1] = E[r2][c2][0] = w;
            }
            else E[r1][c1][2] = E[r2][c2][2] = w;
            Modify(1,1,n,c1,c2);
        }
        else
        {
            int l = getint(),r = getint();
            tp = 0; GetRange(1,1,n,l,r); Ans = stk[1];
            for (int i = 2; i <= tp; i++)
            {
                int U = E[0][Left[i]][0],D = E[1][Left[i]][0];
                Ans = Merge(Ans,stk[i],U + D,min(U,D));
            }
            printf("%d\n",Ans.a[0]);
        }
    }
    return 0;
}

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