首页 > 其他分享 >洛谷 P8426 [JOI Open 2022] 放学路(School Road)

洛谷 P8426 [JOI Open 2022] 放学路(School Road)

时间:2024-01-17 16:12:41浏览次数:29  
标签:School 洛谷 v1 int ll cnt P8426 v2 maxn

洛谷传送门

LOJ 传送门

考虑整个图是一个点双怎么做。

显然如果有重边并且两条边边权一样就寄了。否则我们可以把它们当成一条边。

考虑一个二度点 \(u\) 和与它相连的边 \((v, u), (u, w)\)。我们可以把它缩成边 \((v, w)\)。如果新边已经存在并且边权不等于这两条边边权就寄了。缩点可能会产生一些新的二度点,用队列维护。

剩下的点除了 \(1, n\) 是度数 \(\ge 3\) 的点。可以证明如果最后有度数 \(\ge 3\) 的点就一定不行。因为可以得出一条边的边权为 \(0\),与题设矛盾。

考虑整个图不是点双。考虑添加边 \((1, n, \text{dis}(1, n))\)。只保留和 \(1, n\) 在同一个点双的点即可。因为不在就不能从 \(1\) 到这个点再到 \(n\)。

然后就转化成了整个图是一个点双,用上面的做法即可。

时间复杂度 \(O((n + m) \log n)\)。

code
#include <bits/stdc++.h>
#define pb emplace_back
#define fst first
#define scd second
#define mkp make_pair
#define mems(a, x) memset((a), (x), sizeof(a))

using namespace std;
typedef long long ll;
typedef double db;
typedef unsigned long long ull;
typedef long double ldb;
typedef pair<ll, ll> pii;

const int maxn = 200100;

ll n, m, deg[maxn];
vector<pii> G[maxn];
set<pii> T[maxn];

struct node {
	ll u, d;
	node(ll a = 0, ll b = 0) : u(a), d(b) {}
};

inline bool operator < (const node &a, const node &b) {
	return a.d > b.d;
}

ll f[maxn];
bool vis[maxn];

int dfn[maxn], low[maxn], tim, cnt, stk[maxn], top;
vector<int> S[maxn];

void dfs(int u, int fa) {
	dfn[u] = low[u] = ++tim;
	stk[++top] = u;
	for (pii p : G[u]) {
		ll v = p.fst;
		if (v == fa) {
			continue;
		}
		if (!dfn[v]) {
			dfs(v, u);
			low[u] = min(low[u], low[v]);
			if (low[v] >= dfn[u]) {
				++cnt;
				while (1) {
					int x = stk[top--];
					S[cnt].pb(x);
					if (x == v) {
						break;
					}
				}
				S[cnt].pb(u);
			}
		} else {
			low[u] = min(low[u], dfn[v]);
		}
	}
}

void solve() {
	scanf("%lld%lld", &n, &m);
	while (m--) {
		ll u, v, d;
		scanf("%lld%lld%lld", &u, &v, &d);
		G[u].pb(v, d);
		G[v].pb(u, d);
	}
	priority_queue<node> pq;
	mems(f, 0x3f);
	f[1] = 0;
	pq.emplace(1, 0);
	while (pq.size()) {
		int u = pq.top().u;
		pq.pop();
		if (vis[u]) {
			continue;
		}
		vis[u] = 1;
		for (pii p : G[u]) {
			ll v = p.fst, d = p.scd;
			if (f[v] > f[u] + d) {
				f[v] = f[u] + d;
				if (!vis[v]) {
					pq.emplace(v, f[v]);
				}
			}
		}
	}
	G[1].pb(n, f[n]);
	G[n].pb(1, f[n]);
	dfs(1, -1);
	mems(vis, 0);
	for (int i = 1; i <= cnt; ++i) {
		bool f1 = 0, f2 = 0;
		for (int u : S[i]) {
			f1 |= (u == 1);
			f2 |= (u == n);
		}
		if (f1 && f2) {
			for (int u : S[i]) {
				vis[u] = 1;
			}
		}
	}
	for (int u = 1; u <= n; ++u) {
		if (!vis[u]) {
			continue;
		}
		for (pii p : G[u]) {
			ll v = p.fst, d = p.scd;
			if (vis[v]) {
				auto it = T[u].lower_bound(mkp(v, -1));
				if (it != T[u].end() && it->fst == v && it->scd != d) {
					puts("1");
					return;
				}
				T[u].emplace(v, d);
			}
		}
		deg[u] = (int)T[u].size();
	}
	queue<int> q;
	int cnt = 0;
	for (int i = 2; i < n; ++i) {
		cnt += vis[i];
		if (deg[i] == 2) {
			q.push(i);
		}
	}
	while (q.size()) {
		--cnt;
		int u = q.front();
		q.pop();
		pii p1 = *T[u].begin(), p2 = *(--T[u].end());
		ll v1 = p1.fst, d1 = p1.scd, v2 = p2.fst, d2 = p2.scd;
		T[v1].erase(mkp(u, d1));
		T[v2].erase(mkp(u, d2));
		auto it = T[v1].lower_bound(mkp(v2, -1));
		if (it != T[v1].end() && it->fst == v2) {
			if (it->scd != d1 + d2) {
				puts("1");
				return;
			}
			T[v2].erase(mkp(v1, it->scd));
			T[v1].erase(it);
			T[v1].emplace(v2, d1 + d2);
			T[v2].emplace(v1, d1 + d2);
			if ((--deg[v1]) == 2 && v1 != 1 && v1 != n) {
				q.push(v1);
			}
			if ((--deg[v2]) == 2 && v2 != 1 && v2 != n) {
				q.push(v2);
			}
		} else {
			T[v1].emplace(v2, d1 + d2);
			T[v2].emplace(v1, d1 + d2);
		}
	}
	puts(cnt ? "1" : "0");
}

int main() {
	int T = 1;
	// scanf("%d", &T);
	while (T--) {
		solve();
	}
	return 0;
}

标签:School,洛谷,v1,int,ll,cnt,P8426,v2,maxn
From: https://www.cnblogs.com/zltzlt-blog/p/17970252

相关文章

  • 洛谷题单指南-模拟和高精度-P1042 [NOIP2003 普及组] 乒乓球
    原题链接:https://www.luogu.com.cn/problem/P1042题意解读:分别针对11分制和21分制,输出每局比分。只需要判断一局的结束条件:得分高者如果达到11或者21,且比分间隔大于等于2分,则表示一局结束,可开始下一局,用模拟法即可解决。100分代码:#include<bits/stdc++.h>usingnamespaces......
  • 洛谷P10058 题解
    这种翻转的题明显已经做烂了好吧……首先显而易见,翻转偶数次对结果没有影响,只需要考虑奇数次翻转的情况。由于是整体移动的操作,可以抓住一个点来移动,然后还原出原来的序列。需要注意的是字符串是环形移动,因此如果当前点的位置大于字符串长度,要对字符串的长度进行取余操作。写......
  • 洛谷比赛【LGR-171-Div.3】深圳科创学院基础赛 #7 &「RHOI」Round 2 赛后总结
    洛谷比赛【LGR-171-Div.3】深圳科创学院基础赛#7&「RHOI」Round2赛后总结比赛链接:https://www.luogu.com.cn/contest/146495建议先看原题再看文章。A-Water(P10056)有\(n\)个杯子,每个杯子的容积是\(a\),且初始装有\(b\)体积水。你可以进行任意次操作,每次操作选择任......
  • 洛谷 P5359 [SDOI2019] 染色
    洛谷传送门LOJ传送门dp好题。首先有一个显然的状态,设\(f_{i,x,y}\)为第\(i\)列上下两格的颜色分别为\(x,y\)的方案数。但是这样做时间复杂度至少为\(O(nm^2)\),无法接受。注意到全\(0\)列的转移是重复的。我们可以试着只在两个相邻非全\(0\)列转移。这样我们需......
  • 洛谷 P5996 [PA2014] Muzeum
    洛谷传送门考虑最大权闭合子图,第\(i\)个手办建点\(i\),第\(i\)个警察建点\(i'\)。我们有一些边:\(\foralli,(S,i,v_i),(i',T,v_i)\),以及对于能看见第\(i\)个手办的第\(j\)个警察,有\((i,j',\infty)\)。手办的\(\sumv_i\)减去最小割(最大流)即为答案。考虑转换......
  • 《大学计算机》课程简介 School of Computer Science and Engineering
    《大学计算机》课程简介SchoolofComputerScienceandEngineering阅读量:1630     发布时间:2014-05-25分享到: 《大学计算机》课程是大学计算机基础教学的最基本课程,是大学本科非计算机专业学生必修的公共基础课。计算机基础课程如同数学、外语一样,其教学内......
  • 双向广搜->字符变换(洛谷P1032)
    题意:给起始和终止串A和B,以及不超过6个字符串变换规则,求A->B能否在10步以内变换完成。分析:暴力bfs每次有6条路可以走,时间复杂度是6^10大概6e8的时间复杂度,会TLE。于是这题是一道经典的双向bfs。直接开两个队列,两个map,暴力搜1~5步即可。双向bfs的时间复杂度是2*(6^5)=1e4......
  • 洛谷 P7409 SvT
    洛谷传送门考虑对反串建SAM,设\([i,n]\)的后缀对应SAM的点是\(a_i\)。那么\(\text{lcp}(s[i:n],s[j:n])=\text{len}(\text{lca}(a_i,a_j))\)。于是问题变成了,给定一些点,统计两两\(\text{lca}\)点权之和。考虑建虚树,枚举每个点\(u\)作为\(\text{lca}\)的......
  • 洛谷火柴人
    importjava.io.BufferedReader;importjava.io.InputStreamReader;importjava.io.StreamTokenizer;publicclassMain{staticintn;staticintnumber=0;staticint[]arr=newint[20000];staticboolean[]st=newboolean[20000];sta......
  • 【LGR-170-Div.3】洛谷基础赛 #6 & Cfz Round 3 & Caféforces #2
    这套题感觉质量很高A.Battle\[x\equivr(\bmodP)\]\[P\midx-r\]因此只有第一次操作是有效的voidsolve(){ intn,m,p; cin>>n>>m>>p; m-=m%p; if(!m)puts("Alice"); else{ n-=n%p; if(!n)puts("Bob"); else......