首页 > 其他分享 >Codeforces Round 406 (Div. 2) D. Legacy 线段树优化建图

Codeforces Round 406 (Div. 2) D. Legacy 线段树优化建图

时间:2023-09-06 11:02:39浏览次数:86  
标签:std val int Codeforces mid 406 建图 号点 dis

传送门

题目大意:

给定n个点,m个操作,和起点s。其中n 和 q 大于等于1小于等于1e5, s大于等于1小于等于n

其中m个操作有三种情况:

  1.输入1 u v val 表示从u号点向v号点连一个权值为val的有向边,其中1 <= u <= n, 1 <= v <= n, 1 <= val <= 1e9

  2.输入2 u l r val 表示从u号点向区间[l, r]所有的点连一个权值为val的有向边,其中1 <= u <= n, 1 <= l <= r <= n, 1 <= val <= 1e9

  3.输入3 u l r val 表示从区间[l, r]所有的点向u连一个权值为val的有向边,其中1 <= u <= n, 1 <= l <= r <= n, 1 <= val <= 1e9

最后求从起点s出发能到达所有点的最短距离,如果无法到达输出-1

解题思路:

  区间问题可以联想到线段树。

看操作2如何处理,如果我们拥有一种这种类似于线段树的图形结构。假设n为8,我们让所叶子的编号都是从1-n,也就是让叶子代表1-n这些点。

如果我们如图所示连了边权为0的有向边,那么要表示从2号点向[3, 4]这个区间连了权值为5的有向边就可以表示为2到12号点连了边权为5的有向边。因为12号点向3和4号点连了边权为0的有向边也就是说12号点可以到达3和4号点,那么如果3号向区间[5, 6]也就是编号14的点的连了条边权为6的有向边,如果我们从2号点出发能否求出到达5, 6号点的最短路呢?很显然是可以的,2会达到12号点,那么到达12号点的最短路为5,12号点能到达3号点,于是可以算出到达3号点的最短路为5,3号点能到达14号点,所以到达14号点的最短路为11,14号点能到达5, 6号点且边权为0,所以到达5, 6号点的最短路为11。

接下来看操作三如何处理,还是假设n为8的情况。我们有这样一个图,分析方法和操作2一样可以自己试试。

  也就是说我们建出这样的图,再根据题目要求连边跑一遍最短路就可以解出答案了。

#include <bits/stdc++.h>

using ll = long long;
using ld = long double; 
const int N = 8e5 + 10, M = N << 1;
const ll INF = 0x3f3f3f3f3f3f3f3f;
typedef std::pair<ll, int> PII;
typedef std::array<int, 3> ay;

#define ls tr[u].l
#define rs tr[u].r

struct node {
	int l, r;
}tr[N];

int idx, id;
int h[N << 1], ne[N << 2], e[N << 2], w[N << 2];
ll dis[N];
bool vis[N];
int n, m, s, rt1, rt2;

inline void add(int a, int b, int c) {
	ne[idx] = h[a], e[idx] = b, w[idx] = c, h[a] = idx ++;
}

inline void buildOut(int &u, int L, int R) {
	if (L == R) {
		u = L;
		return ;
	}
	
	u = ++ id;
	int mid = L + R >> 1;
	buildOut(ls, L, mid);
	buildOut(rs, mid + 1, R);
	add(u, ls, 0);
	add(u, rs, 0);
}

inline void buildIn(int &u, int L, int R) {
	if (L == R) {
		u = L;
		return ;
	}
	
	u = ++ id;
	int mid = L + R >> 1;
	buildIn(ls, L, mid);
	buildIn(rs, mid + 1, R);
	add(ls, u, 0);
	add(rs, u, 0);
}

inline void update(int u, int L, int R, int v, int l, int r, int type, int val) {
	if (L >= l && R <= r) {
	 	if (type == 2) add(v, u, val);
	 	else add(u, v, val);
		return ;
	}
	
	int mid = L + R >> 1;
	if (l <= mid) update(ls, L, mid, v, l, r, type, val);
	if (r > mid)	update(rs, mid + 1, R, v, l, r, type, val);
}

inline void Dijkstra() {
	std::priority_queue<PII,  std::vector<PII>, std::greater<PII>> q;
	memset(dis, 0x3f, sizeof dis);
	memset(vis, false, sizeof vis);
	dis[s] = 0;
	q.push({0, s});
	
	while (!q.empty()) {
		int u = q.top().second;
		int VAL = q.top().first;
		q.pop();
		if (vis[u]) continue;
		vis[u] = true;
		for (int i = h[u]; ~i; i = ne[i]) {
			int j = e[i], val = w[i];
			if (dis[u] + val < dis[j]) {
				dis[j] = dis[u] + val;
				q.push({dis[j], j});
			}
		}
	}
}

std::string str;

inline void solve() {
	memset(h, -1, sizeof h);
	std::cin >> n >> m >> s;
	id = n;
	buildOut(rt1, 1, n), buildIn(rt2, 1, n);
	
	while (m --) {
		int op, u, l, r, val;
		std::cin >> op >> u >> l;
		if (op == 1) {
			std::cin >> val;
			add(u, l, val);
		} else if (op == 2) {
			std::cin >> r >> val;
			update(rt1, 1, n, u, l, r, 2, val);
		} else {
			std::cin >> r >> val;
			update(rt2, 1, n, u, l, r, 3, val);
		}
	}
	
	Dijkstra();
	
	for (int i = 1; i <= n; i ++) {
		if (dis[i] != INF)
			std::cout << dis[i] << ' ';
		else std::cout << -1 << ' ';
	}
}

signed main(void) {
	std::ios::sync_with_stdio(false);
	std::cin.tie(nullptr);
	std::cout.tie(nullptr);
	
	int _ = 1;
	
	while (_ --) solve();
	
	return 0;
}

标签:std,val,int,Codeforces,mid,406,建图,号点,dis
From: https://www.cnblogs.com/qdhys/p/17681692.html

相关文章

  • Educational Codeforces Round 154 (Rated for Div. 2)
    EducationalCodeforcesRound154(RatedforDiv.2)比赛链接我都快忘了还有这一场比赛,今天打开cf看见这场比赛正好有时间就补了!!!2023.9.3也许是出去玩了一下午脑子不够用了??怎么现在读题都有一点读不懂了!!!2023.9.4我靠这场我怎么感觉没什么思路呢????A题PrimeDeletion题目链接......
  • Educational Codeforces Round 154 (Rated for Div. 2)
    Preface太FW了现在,纯纯给队伍拖后腿,马上要成为我们队CFRating最低的了但换句话说徐神和祁神都这么猛,我直接躺着被嘎嘎带飞好像也很爽啊不管怎么样还是要多练,不过接下来可能要按专题重点突破了,明天队里开个会确定下大家的主攻方向再说A.PrimeDeletion因为\(13\)和\(31\)都......
  • Lnton 羚通算法算力云平台如何在 OpenCV-Python 中使用 cvui 库创建图像
    CVUI之图像Pythonimportnumpyasnpimportcv2importcvuidefimage_test():WINDOW_NAME='Image-Test'#创建画布frame=np.zeros((400,600,3),np.uint8)#读取图像image=cv2.imread("lena-face.jpg",cv2.IMREAD_COLOR)......
  • Educational Codeforces Round 23 A - F
    EducationalCodeforcesRound23目录EducationalCodeforcesRound23A-TreasureHuntB-MakesAndTheProductC-ReallyBigNumbersD-ImbalancedArrayE-ChoosingTheCommanderF-MEXQueriesA-TreasureHunt往四个方向走,每次操作会变动横坐标和纵坐标,横纵坐标......
  • Educational Codeforces Round 154 (Rated for Div. 2)(A—C)
    A.PrimeDeletion思路:从1到9,每个数后面都可以加一个数构成一个含有两个数的质数,只需要从s[1]~s[9]中找到一个数与s[0]构成质数即可代码实现/*******************************|Author:CHC|Problem:A.PrimeDeletion|Contest:Codeforces-EducationalCodeforcesR......
  • 【题解】Educational Codeforces Round 153(CF1860)
    每次打都想感叹一句,Educational名不虚传。A.NotaSubstring题目描述:有\(t\)组数据,对于每一组数据,你需要判断能否构造一个只由左右括号组成且长度为已经给定字符串的\(2\)倍且已经给定的字符串不是子串的合法字符串。注:合法的字符串是左右括号能完全匹配的字符串。如果能,......
  • Educational Codeforces Round 113
    稳定发挥4题A题文件输出没去掉WA了一发B题特殊情况没判到,WA了好几发,中间还交到D题去了C题简单判断一下无解,然后组合数求一下就行D题其实也挺简单的,考虑严格夹在两条竖线之间的点(不包括边界),如果它们不是在同一水平线上,则必然大于Manhattan距离,而且两个点对之间要么是x方向走多......
  • 常见优化建图技巧
    一、线段树优化建图基本操作:\(x\)向区间\([l,r]\)连边区间\([l,r]\)向\(x\)连边区间\([l,r]\)向区间\([x,y]\)连边建立两棵线段树,一棵从父亲节点向儿子节点连长度为\(0\)的边,称为出树;一棵从儿子节点向父亲连长度为\(0\)的边,称为入树。并且在出树和入树的......
  • Educational Codeforces Round 154 (Rated for Div. 2)
    感觉edu的题目都比较有新意;A.PrimeDeletion题意:给定长度为9的数,且1-9每个数字出现一次,求按照原定顺序选几个数组成的质数(起码选择两个);下意识写了一个dfs,过了;1#include<bits/stdc++.h>2usingnamespacestd;3intread(){4charch=getchar();intx=0,f=1;5......
  • Educational Codeforces Round 123
    A.DoorsandKeys#include<bits/stdc++.h>usingnamespacestd;#defineintlonglongvoidsolve(){strings;cin>>s;map<char,int>pos;for(inti=0;i<6;i++)pos[s[i]]=i;if(pos['r&......