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 31 22 13 1 2Q 1 3C 1 2 2 2 3Q 2 3

Sample Output

75

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\n",ans);
        }
    }
}
时间: 2024-08-09 06:23:08

SDOI2015 道路修建的相关文章

BZOJ 3995 Sdoi2015 道路修建 线段树

题目大意:给定一个2*n的网格图,多次改变某条边的权值或询问y坐标在[l,r]中的2*(r-l+1)个点的MST 这真是一道好题= = 我们用线段树维护每个区间内的MST 然后考虑合并 合并两个区间 我们会加入两条边 这样一定会形成一个环 切掉环上最大边 这题没了 然后就是一坨乱七八糟的细节讨论= = 首先最大边一定在图中的彩色部分内 绿色部分可以O(1)求 我们需要维护的是红色和蓝色部分 然后如果切掉的边是横边或者切掉的竖边不是区间唯一的竖边(如图中蓝色竖边) 那么红框和蓝框直接用左右区间的即

【线段树】bzoj3995 [SDOI2015]道路修建

线段树每个结点维护5个域: 整个区间的MST. 将两个左端点连通,两个右端点不连通,整个区间内选择2*(r-l+1)-2条边的最小生成森林,有两个连通块. 将两个右端点连通,两个左端点不连通,整个区间内选择2*(r-l+1)-2条边的最小生成森林,有两个连通块. 两个左端点不连通,两个右端点也不连通,整个区间内选择2*(r-l+1)-2条边的最小生成森林,有两个连通块.(就是上面一条线,下面一条线) 两个左端点不连通,两个右端点也不连通,整个区间内选择2*(r-l+1)-3条边的最小生成森林,有

bzoj3995[SDOI2015]道路修建

http://www.lydsy.com/JudgeOnline/problem.php?id=3995 线段树维护连通性. 我们发现,对于一个区间[L,R],我们只需要知道(1,L),(2,L),(1,R)和(2,R)这4个点的之间的连通情况即可. 我们在线段树中,假设当前节点的表示的区间的为[L,R],我们需要知道(1,L),(2,L),(1,R)和(2,R)这4个点的之间的连通情况,但是为了方便,我们记了(1,L),(2,L),(1,R+1)和(2,R+1)这4个点的连通情况. 每个节点记

[BZOJ 3995] [SDOI2015] 道路修建 【线段树维护连通性】

题目链接:BZOJ - 3995 题目分析 这道题..是我悲伤的回忆.. 线段树维护连通性,与 BZOJ-1018 类似,然而我省选之前并没有做过  1018,即使它在 ProblemSet 的第一页. 更悲伤的是,这道题有 40 分的暴力分,写个 Kruskal 就可以得到,然而我写了个更快的 DP . 这本来没有什么问题,然而我的 DP 转移少些了一种情况,于是...爆零.没错,省选前20名可能就我没有得到这 40 分? 不想再多说什么了...希望以后不要再这样 SB 了,如果以后还有机会的

【BZOJ-2435】道路修建 (树形DP?)DFS

2435: [Noi2011]道路修建 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 3115  Solved: 1002[Submit][Status][Discuss] Description 在 W 星球上有 n 个国家.为了各自国家的经济发展,他们决定在各个国家之间建设双向道路使得国家之间连通.但是每个国家的国王都很吝啬,他们只愿意修建恰好 n – 1条双向道路. 每条道路的修建都要付出一定的费用, 这个费用等于道路长度乘以道路两端的国家

A1. 道路修建 Small(BNUOJ)

A1. 道路修建 Small Time Limit: 1000ms Memory Limit: 131072KB 64-bit integer IO format: %lld      Java class name: Main Submit Status 无向图初始有个点,从到依次标号,但是没有边, 接下来有次操作,从到依次标号,你需要对每种操作输出相应的结果,操作分为两种: 输入格式 操作说明 输出结果 0_u_v 加入一条连接标号为和标号为的点的边. 输出加边后图中连通块的个数. 1_u_

bzoj2435[Noi2011]道路修建

bzoj2435[Noi2011]道路修建 题意: 给个n点树,每条边的费用为这条边两端的节点数的差值*这条边的长度,求这个数的总费用. 题解: 水题,dfs求出节点的子树大小sz,对于每一条边,费用为深度大的sz值与n-sz相减的绝对值乘边的长度. 代码: 1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #define inc(i,j,k) for(int i=j;i<=k;i+

2435: [Noi2011]道路修建(求助!!!)

2435: [Noi2011]道路修建 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2188  Solved: 639[Submit][Status] Description 在 W 星球上有 n 个国家.为了各自国家的经济发展,他们决定在各个国家之间建设双向道路使得国家之间连通.但是每个国家的国王都很吝啬,他们只愿意修建恰好 n – 1条双向道路. 每条道路的修建都要付出一定的费用, 这个费用等于道路长度乘以道路两端的国家个数之差的绝对值.例

【NOI2011】道路修建 BFS

[NOI2011]道路修建 Description 在 W 星球上有 n 个国家.为了各自国家的经济发展,他们决定在各个国家之间建设双向道路使得国家之间连通.但是每个国家的国王都很吝啬,他们只愿意修建恰好 n – 1条双向道路. 每条道路的修建都要付出一定的费用, 这个费用等于道路长度乘以道路两端的国家个数之差的绝对值.例如,在下图中,虚线所示道路两端分别有 2 个.4个国家,如果该道路长度为 1,则费用为1×|2 – 4|=2.图中圆圈里的数字表示国家的编号. 由于国家的数量十分庞大,道路的建