首页 > 其他分享 >P5618 SDOI2015 道路修建题解

P5618 SDOI2015 道路修建题解

时间:2024-01-22 22:46:16浏览次数:30  
标签:min 题解 rs v1 v2 P5618 v4 SDOI2015 ls

题目分析

虽然数据范围只有 \(n\le60000\),但是完全可以直接用线段树做。

首先考虑那种状态的图在左边和右边加入节点和边之后可以连通。容易发现,这种图有这两个性质:

  • 至少有一条路径,经过最左端和最右端中的点。
  • 所有点至少和最左端和最右端的点连通。

于是可以划分成以下几种状态:

  1. 最左端两个点不连通,最右端两个点不连通,只有一条经过最左端和最右端中的点的路径;
  2. 最左端两个点连通,最右端两个点不连通;
  3. 最左端两个点不连通,最右端两个点连通;
  4. 最左端两个点连通,最右端两个点连通;
  5. 最左端两个点不连通,最右端两个点不连通,有两条经过最左端和最右端中的点的路径。

如图:

状态

然后分类讨论每两种状态的连接方法和结果状态,如图所示的几种情况:

剩余情况见代码 pushup 函数。

用线段树维护,记录以下东西:

  • \(a,b\):区间左端点和又端点。
  • \(v1,v2,v3,v4,v5\):区间中每种状态最小费用。

对于竖边修改,修改包含需要修改的点的区间;对于横边修改,只需修改列数较小的点即可。

查询输出对应区间的 \(v4\) 的。

这里有个坑点:输入修改操作时可能把列数大的点放在前面,这时要把较小的点设为后输入的点。

示例代码

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;

const int N = 60005, INF = 2e9;

int n, m;
int x[N], y[N], z[N];
struct node{
	int a, b;
	LL v1, v2, v3, v4, v5;
}t[N * 4];

void pushup(node &u, node ls, node rs)
{
	int p = x[ls.b], q = y[ls.b], c = p + q, d = min(p, q);
	u.v1 = u.v2 = u.v3 = u.v4 = u.v5 = INF;
	u.v1 = min(u.v1, ls.v1 + rs.v2 + c);
	u.v3 = min(u.v3, ls.v1 + rs.v4 + c);
	u.v1 = min(u.v1, ls.v1 + rs.v5 + c);
	u.v2 = min(u.v2, ls.v2 + rs.v2 + c);
	u.v4 = min(u.v4, ls.v2 + rs.v4 + c);
	u.v2 = min(u.v2, ls.v2 + rs.v5 + c);
	u.v1 = min(u.v1, ls.v3 + rs.v1 + c);
	u.v1 = min(u.v1, ls.v3 + rs.v2 + d);
	u.v3 = min(u.v3, ls.v3 + rs.v3 + c);
	u.v3 = min(u.v3, ls.v3 + rs.v4 + d);
	u.v3 = min(u.v3, ls.v3 + rs.v5 + c);
	u.v1 = min(u.v1, ls.v3 + rs.v5 + d);
	u.v2 = min(u.v2, ls.v4 + rs.v1 + c);
	u.v2 = min(u.v2, ls.v4 + rs.v2 + d);
	u.v4 = min(u.v4, ls.v4 + rs.v3 + c);
	u.v4 = min(u.v4, ls.v4 + rs.v4 + d);
	u.v4 = min(u.v4, ls.v4 + rs.v5 + c);
	u.v2 = min(u.v2, ls.v4 + rs.v5 + d);
	u.v1 = min(u.v1, ls.v5 + rs.v1 + c);
	u.v2 = min(u.v2, ls.v5 + rs.v2 + c);
	u.v1 = min(u.v1, ls.v5 + rs.v2 + d);
	u.v3 = min(u.v3, ls.v5 + rs.v3 + c);
	u.v4 = min(u.v4, ls.v5 + rs.v4 + c);
	u.v3 = min(u.v3, ls.v5 + rs.v4 + d);
	u.v5 = min(u.v5, ls.v5 + rs.v5 + c);
	u.v1 = min(u.v1, ls.v5 + rs.v5 + d);
	u.a = ls.a, u.b = rs.b;
}

void build(int u, int a, int b)
{
	t[u].a = a, t[u].b = b;
	if(a == b)
	{
		t[u].v1 = t[u].v2 = t[u].v3 = INF;
		t[u].v5 = 0;
		t[u].v4 = z[a];
		return ;
	}
	int mid = a + b >> 1, ls = u << 1, rs = ls | 1;
	build(ls, a, mid), build(rs, mid + 1, b);
	pushup(t[u], t[ls], t[rs]);
}

void modify(int u, int d)
{
	if(t[u].a == t[u].b)
	{
		t[u].v1 = t[u].v2 = t[u].v3 = INF;
		t[u].v5 = 0;
		t[u].v4 = z[t[u].a];
		return ;
	}
	int ls = u << 1, rs = ls | 1;
	if(t[ls].b >= d) modify(ls, d);
	else modify(rs, d);
	pushup(t[u], t[ls], t[rs]);
}

node query(int u, int x, int y)
{
	if(x <= t[u].a && t[u].b <= y) return t[u];
	int ls = u << 1, rs = ls | 1;
	if(t[ls].b >= x && t[rs].a <= y)
	{
		node res;
		pushup(res, query(ls, x, y), query(rs, x, y));
		return res;
	}
	else if(t[ls].b >= x) return query(ls, x, y);
	else return query(rs, x, y);
}

int main()
{
	scanf("%d%d", &n, &m);
	for(int i = 1; i < n; i ++ ) scanf("%d", &x[i]);
	for(int i = 1; i < n; i ++ ) scanf("%d", &y[i]);
	for(int i = 1; i <= n; i ++ ) scanf("%d", &z[i]);
	
	build(1, 1, n);
	while(m -- )
	{
		char op[2];
		scanf("%s", op);
		if(*op == 'Q')
		{
			int l, r;
			scanf("%d%d", &l, &r);
			printf("%lld\n", query(1, l, r).v4);
		}
		else
		{
			int ax, bx, ay, by, w;
			scanf("%d%d%d%d%d", &ay, &ax, &by, &bx, &w);
			if(ax == bx)
			{
				z[ax] = w;
				modify(1, ax);
			}
			else
			{
				if(ax > bx) ax = bx;
				if(ay == 1) x[ax] = w;
				else y[ax] = w;
				modify(1, ax);
			}
		}
	}
	return 0;
}

标签:min,题解,rs,v1,v2,P5618,v4,SDOI2015,ls
From: https://www.cnblogs.com/recollect-the-past/p/17981258

相关文章

  • [ARC155C] Even Sum Triplet 题解
    一道大分类讨论。如果有一个可以交换的段包含奇数,那么你可以把所有奇数移到最左边并任意调整相对顺序,然后回到任意一种有一个可以交换的段包含奇数的状态。这种情况,如果偶数的数量为\(2\),这两个偶数是不能交换相对位置的,有至少\(3\)个偶数就能交换偶数间相对位置。所以只需要......
  • P7618 [COCI2011-2012#2] FUNKCIJA 题解
    看起来比较复杂,但实际上是一个树上dp的模型。因为每一重循环都最多有一个依赖,可以转化为树上的父子关系,于是就形成了一个森林。对于非叶子节点,设\(f_{u,i}\)表示第\(u\)循环变量的值是\(i\)时所有直接或间接依赖于它的循环变量(即以它为根的子树除开它的部分)循环次数,对非......
  • 题解-[ABC288D] Range Add Query
    题目:[ABC288D]RangeAddQuery-洛谷|计算机科学教育新生态(luogu.com.cn) 大意:一些数,选一个区间A(L~R),并再选一个区间B(长度k),这个区间B的每个数加减(加负数=减一个数)一个数,最终使得区间A全部数为0举个例(样例)0.   3-11-2201.  0-4-2-220 (-3)2.  ......
  • 2024 蓝桥杯模拟赛 1 (div1) 题解
    A.把字符串小写转换成大写即可#include<bits/stdc++.h>usingnamespacestd;voidsolve(){strings;cin>>s;for(inti=0;i<s.size();i++){if(s[i]>='a'&&s[i]<='z'){s[i]=(char)(s[i]-'a......
  • 2024 省选联测部分题解
    目录目录R15T1树V图R15T2矩阵缺失题目:R15T3.R15T1树V图原题:SNOI2024D1T1.注意到答案肯定是形如每个连通块选一个点组成,把连通块缩起来后令\(dp_{u,x}\)表示连通块\(u\)选\(x\)的方案数,每次合并子树转移即可.因为只有\(n^2\)个合法点对所以时间复杂度......
  • R语言包安装失败常见问题解决
    更改或指定镜像源出现这个问题很有可能是你现在用的镜像中未纳入这个包,一是可以多换个源试试。如:install.packages('package-name',repos='http://cran.us.r-project.org')或,在Rstudio中可以:或,命令行可直接指定Rstudio:install.packages('package_name',dependencies=TRUE......
  • 【问题解决】Kafka报错 Bootstrap broker x.x.x.x:9092 (id: -1 rack: null) disconne
    【问题解决】Kafka报错Bootstrapbrokerx.x.x.x:9092(id:-1rack:null)disconnected和服务器连接已经断开。可能kafka服务器停止问题复现近日针对某一客户需求开发了一个需要使用Kafka的功能,功能是什么暂且不论,在本地虚机的Kafka连接一切正常遂放到测试服务器上验证功......
  • Kafka【问题 02】KafkaTemplate 报错 Bootstrap broker localhost:9092 (id: -1 rack:
    Kafka【问题02】KafkaTemplate报错Bootstrapbrokerlocalhost:9092(id:-1rack:null)disconnected问题解决1.报错信息主要的报错信息:Connectiontonode-1(localhost/127.0.0.1:9092)couldnotbeestablished.Brokermaynotbeavailable.和Bootstrapbrok......
  • CF1920E 题解
    CF1920E被这种题卡了,脸都不要了。仔细读题,发现序列可以分成两部分(\(0\)和\(1\))来考虑。在合法序列中,对于一个\(1\),它产生的子串贡献一定是(假设与上一个\(1\)之间有\(x\)个\(0\),与下一个\(1\)之间有\(y\)个\(0\)):\[(x+1)(y+1)\]如果去DP这\(n\)个\(1\),易得转......
  • CF455D Serega and Fun 题解
    题目链接:CF或者洛谷本题是可以用平衡树去做的,具体的为每个\(k\)开一棵平衡树去维护相对位置,而这种移动操作用平衡树维护又是很容易做到的,这种做法是双\(log\)。在\(1e5\)的数据下,我们来说说好写的分块该如何去写。黑色的代表一个块,考虑暴力修改情况,假如原来的数字为\([1......