【YBT2023寒假Day8 C】图论题(图论)(并查集)(线段树合并)

图论题

题目链接:YBT2023寒假Day8 C

题目大意

给你一个无向图,然后你会一直操作直到无法操作,每次找出一个满足条件的三元组 (a,b,c),满足 a<b<c,a,b 与 a,c 之间有边,b,c 之间没有边,然后进行操作把 b,c 连边。
然后问你最后的图有多少种用 n 种颜色染色的方案使得每条边连着的两个点颜色都不同。

思路

首先考虑如果最后的图你知道了要怎么染色。
发现按编号从小到大加入似乎没有头猪,考虑反着过来。

发现反着有一个什么优点呢,就是它可以很好的利用上性质。
那你对于一个点 x,它如果跟后面的边连了 y1,y2,...,ym,那根据我们操作的方法,我们会知道 y1,y2,...,ym 之间是两两连边的。
那它们的染色一定就是两两不同的,那你 x 这个点只要跟它们都不同就行。
那我们设 dii 点有多少条连向编号比 i 大的点,染色方案就是:i=1n(ndi)

那我们看怎么求 di 即可。


考虑我们直接看是否能找到一个 (x,y)(x<y) 有边的充要条件。
你看到中间的媒介点有 <x,<y 的条件,那你考虑猜测是不是要存在一条 xy 的路径使得路径上的点除了 x,y 别的编号都 <x
考虑证明:

充分性:如果存在这么一条路径 x,p1,p2,...,pm,y,找到这些点中编号最小的点 pk
那对于 pk1,pk+1 编号都大于它而且跟它连边。
那他两就可以连边,pk 就可以不要了。
那最后就只会剩下 x,y,也就是说明有边了。

必要性:(x,y) 要么直接有边,要么就是由 (k,x),(k,y)(k<x<y) 生成。
那归纳一下,(k,x) 的有边要么直接有,要么再由一个编号 <k 的生成,(k,y) 同理。
假设由生成的全部递归下去,最后会拆成若干条边(组成路径),而这些边它的编号限制越来越小,也就肯定小于一开始的 x


于是你设 Ax 集合是原图中所有跟 x 连边且编号比 x 大的。
Si 则是加边之后的图的。
然后 Si 通过上面的结论,就是 x 只走编号比 x 小的点能到达的点的 Ax 的并集中 >x 的部分。
那找 >x 的部分可以用线段树维护每个的数量。
那至于集合的并,我们可以用并查集维护边形成的连通块,然后合并的时候我们可以用线段树合并来搞。

代码

#include <bits/stdc++.h> #define mo 998244353 #define ll long long namespace quickio { const int bufferSize = 1 << 20; char br[bufferSize], *tailr = br, *headr = br; inline char nextChar() { if (headr == tailr) tailr = (headr = br) + fread(br, 1, bufferSize, stdin); return headr == tailr ? EOF : *headr++; } char bw[bufferSize], *tailw = bw; inline void printChar(const char &ch) { if (tailw == bw + bufferSize) fwrite(tailw = bw, 1, bufferSize, stdout); *tailw++ = ch; } inline void flush() { if (tailw != bw) fwrite(bw, 1, tailw - bw, stdout); } template <class T> inline void read(T &x) { static char ch; while (!isdigit(ch = nextChar())); x = ch - '0'; while (isdigit(ch = nextChar())) x = x * 10 + ch - '0'; } template <class T> inline void putint(T x) { static char buf[15], *tail = buf; if (!x) printChar('0'); else { for (; x; x /= 10) *++tail = x % 10 + '0'; for (; tail != buf; --tail) printChar(*tail); } } } using quickio::read; using quickio::putint; using quickio::printChar; using namespace std; const int N = 1e6 + 100; int n, m, rt[N], fa[N], d[N]; vector <int> G[N]; struct XD_tree { int ls[N << 6], rs[N << 6], f[N << 6], tot; void up(int now) { f[now] = f[ls[now]] + f[rs[now]]; } void insert(int &now, int l, int r, int pl) { if (!now) now = ++tot; if (l == r) { f[now] = 1; return ; } int mid = (l + r) >> 1; if (pl <= mid) insert(ls[now], l, mid, pl); else insert(rs[now], mid + 1, r, pl); up(now); } int query(int now, int l, int r, int L, int R) { if (!now) return 0; if (L <= l && r <= R) return f[now]; int mid = (l + r) >> 1, re = 0; if (L <= mid) re += query(ls[now], l, mid, L, R); if (mid < R) re += query(rs[now], mid + 1, r, L, R); return re; } int merge(int x1, int x2, int l, int r) { if (!x1 || !x2) return x1 + x2; if (l == r) { f[x1] |= f[x2]; return x1; } int mid = (l + r) >> 1; ls[x1] = merge(ls[x1], ls[x2], l, mid); rs[x1] = merge(rs[x1], rs[x2], mid + 1, r); up(x1); return x1; } }T; int find(int now) { if (fa[now] == now) return now; return fa[now] = find(fa[now]); } int main() { freopen("graph.in", "r", stdin); freopen("graph.out", "w", stdout); // scanf("%d %d", &n, &m); read(n); read(m); for (int i = 1; i <= m; i++) { // int x, y; scanf("%d %d", &x, &y); int x, y; read(x); read(y); if (x < y) swap(x, y); G[x].push_back(y); T.insert(rt[y], 1, n, x); } for (int i = 1; i <= n; i++) fa[i] = i; for (int i = 1; i <= n; i++) { for (int j = 0; j < G[i].size(); j++) { int x = G[i][j]; int X = find(i), Y = find(x); if (X == Y) continue; rt[Y] = T.merge(rt[Y], rt[X], 1, n); fa[X] = Y; } d[i] = T.query(rt[find(i)], 1, n, i + 1, n); } ll ans = 1; for (int i = 1; i <= n; i++) ans = ans * (n - d[i]) % mo; putint((int)ans); // printf("%lld", ans); quickio::flush(); return 0; }

__EOF__

本文作者あおいSakura
本文链接https://www.cnblogs.com/Sakura-TJH/p/YBT2023Day8_C.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   あおいSakura  阅读(14)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
历史上的今天:
2022-02-08 【YBT2022寒假Day3 C】毒瘤染色(LCT)(圆方树)(容斥)
2022-02-08 【YBT2022寒假Day3 B】【LOJ 2460】欧拉回路 / 桥(二分)(欧拉回路)(网络流)
2022-02-08 【YBT2022寒假Day3 A】森林之和(prufer序列)(DP)
2021-02-08 GDKOI2021 爆炸记
点击右上角即可分享
微信分享提示