当前位置: 首页 > news >正文

2640. QYQ在艾泽拉斯

写在前面: 这道题目太恶心了!!!

一些约定


S T L STL STL

  • 因为 xc 不允许我们使用 STLSTLSTL, 所以作者手打了一个 STL

代码

namespace STL {	template <class T> inline void swap(T& a, T& b) { T t = a; a = b; b = t; }template <class T, class Cmp> inline void _qsort(T* data, int left, int right, Cmp q) {if (left >= right) return;T pivot = data[(left + right) / 2];swap(data[(left + right) / 2], data[left]);register int i = left + 1, j = right;while (i <= j) {while (i <= j && q(data[i], pivot)) i++;while (i <= j && q(pivot, data[j])) j--; if (i < j) swap(data[i], data[j]), i++, j--;else break;}swap(data[left], data[j]), _qsort(data, left, j - 1, q), _qsort(data, j + 1, right, q);}template <class T, class Cmp> inline void sort(T* begin, T* end, Cmp q) { _qsort(begin, 0, (int)(end - begin) - 1, q); }template <class T>class vector {private:T* data; // data valint end_1, end_2; // two end static constexpr int P = 100; // 阈值 void __resize(int __size) { // 内置 resize 扩展 end_2 空间T* __new_vec = new T[end_2 = __size];for (int ___i = 0; ___i < end_1; ___i++) __new_vec[___i] = data[___i]; // 拷贝delete data;data = __new_vec; }void __new(int __size) {__resize(__size + P);}public:vector<T>() {data = NULL; end_1 = end_2 = 0; __new(end_2);}vector<T>(int size, T start_val = T()) {__new(size); end_1 = size;for (int __II  = 0; __II < size; __II++) data[__II] = start_val;}void push_back(T q) {if (end_1 + 1 == end_2) __new(end_2); // 扩容data[end_1++] = q; }void pop_back() {end_1--;}bool empty() const {return end_1 == 0;}int size() const {return end_1;}T& operator[](unsigned long long q) {return data[q];}T& operator[](unsigned long long q) const {return data[q];}T* begin() {return data;}T* end() {return data + end_1;}void resize(int __n) {__new(__n);}};template <class T> struct greater {bool operator()(const T& a, const T& b) {return a > b;}};template <class T> struct less {bool operator()(const T& a, const T& b) {return a < b;}};
}

使用教程

  • 首先在代码前面新加上一行: using namespace STL;
    表示加入 STL 这个命名空间(可能你不懂,但是只要会用就可以)
    或者在调用函数的时候(这里比如调用 sort) 这样写 STL::sort(a, a+n, cmp);
    比如下面的代码
// 上面的STL的内容
int Sort[100];
STL::sort(Sort, Sort + n);// 或者
using namespace STL;
int Sort[100];
sort(Sort, Sort + n);
  • sort 函数的使用是和 STL 里面的 sort一样的
    什么都可以排序,可以传入一个比较函数,仿函数,重载小于运算符
    Tips: 这个版本是不可以使用小于运算符、重载运算符的,要可以的版本叫爸爸
  • 里面有 greaterless 这两个用法也是一样的

重点 vector 的使用

低级用法
STL 里面的 vector一致的, 循环的简化(for(int u : vec)) 也是支持的
高级用法
代码里面有这样的一行

static constexpr int P = 100; // 阈值

阈值是什么?
就是说, vector 满了之后的单次扩展量
比如你要定义一个图 G 空间的限制是 256MB

vector<int> G[100000] // 5个0

那么你可以提高速度 换句话说,阈值越大速度越快(快的还不止一点)
将阈值改为 200 因为 100000×200=2×102×105=2×107100000 \times 200=2\times10^2\times10^5=2\times10^7100000×200=2×102×105=2×107
换算一下空间
2×107个int=2×107×4B=8×107B2\times10^7个int=2\times10^7\times4B=8\times10^7B2×107int=2×107×4B=8×107B
换成 KB
8×107÷1024=78125KB8\times10^7\div1024=78125KB8×107÷1024=78125KB
换成 MB
78125÷1024=76.29MB78125\div1024=76.29MB78125÷1024=76.29MB
空间 76.29MB<256MB76.29MB<256MB76.29MB<256MB 可以开

注意: 上面的 76.29MB 不一定是这个数组的真实空间,可能这个空间会更大,请注意MLE的问题,适当优化阈值

思路(崩溃的心路历程)


1. 使用 Kosaraju 算法进行缩点,将一个强连通分量变成一个点

  • 强连通分量就是有一个有向图,这个图删除任意一条边都可以连通
  • 连通就是这个图里面的任意一个节点都可以到达其他所有节点
  • 既然这个强连通分量是两两可以到达的,我们就将这个图变成 1 个点,这个点的价值就是这个强连通分量上的点的 v 之和

这个操作是绝对不会影响答案的,简单的证明如下

  • 首先这个强连通分量上面的城市一定是可以两两连通的(强连通分量的定义)
  • 根据条件 1,这些城市一定是在同一个岛屿上面
  • QyQ 同学是可以在一个岛屿 上面任意走的,而 v 都是正数,所以 QyQ 同学在同一个岛屿上走到的城市越多越好

根据条件 2,可以推得条件 3 成立,条件 3 成立说明如果你走到了这个强连通分量上面的一个点,那么最优的方法一定是要走完这个强连通分量,所以上面的缩点是成立的!


代码

namespace SolveLink {int s[N], s_tot = 0, color[N], tot, vis[N];star_t<N, M << 1> zheng, fan; // 正反图uf qwq;void calc() {function<void(int)> dfs1 = [&](int u) -> void {vis[u] = 1;for (int i = zheng.head[u]; i; i = zheng.next[i]) if (!vis[zheng.to[i]]) dfs1(zheng.to[i]);s[++s_tot] = u;};function<void(int)> dfs2 = [&](int u) -> void {color[u] = tot; new_v[tot] += v[u];for (int i = fan.head[u]; i; i = fan.next[i]) if (!color[fan.to[i]]) dfs2(fan.to[i]); 		};REP(i, 1, n) if (!vis[i]) dfs1(i);rREP(i, n, 1) if (!color[s[i]]) ++tot, dfs2(s[i]);}void main() {calc();REP(from, 1, n) for (int i = zheng.head[from]; i; i = zheng.next[i]) {int to = zheng.to[i];if (color[from] == color[to]) continue; G.add(color[from], color[to]);}}
}

2. 使用并查集维护连通性


因为题目很明确的告诉我们,当两个点在同一个岛屿的条件是这两个点之间的边看成无向边之后是一个连通图

很显然,可以使用并查集计算在同一个岛屿上的城市


不写代码

除非叫爸爸


3. 对于每一个岛屿,使用 DAG 上面的 dp 计算

  • DAG 是有向无环图
  • 直接 dp 即可

时间复杂度

步骤 1 的时间复杂度是 O(n+m)O(n+m)O(n+m)
步骤 2 的时间复杂度是 O(n+m)O(n+m)O(n+m) 不考虑并查集的时间复杂度
步骤 3 的时间复杂度是 O(n+m)O(n + m)O(n+m)

综上所述,时间复杂度为 O(n+m)O(n+m)O(n+m) 只是常数太大了 oj 上面跑出了 82ms

代码

还是我良心

#include <stdio.h>
#include <ctype.h>
#include <functional>using std::function;#define reg register
#define FOR(i, a, b) for (reg int i = (a); i < (b); i++)
#define REP(i, a, b) for (reg int i = (a); i <= (b); i++)
#define rFOR(i, a, b) for (reg int i = (a); i > (b); i--)
#define rREP(i, a, b) for (reg int i = (a); i >= (b); i--)
#define Pq N
constexpr int N = 100010, M = 1000010;namespace fast_io
{// 数组下标从 0 开始char buf[1 << 23], *p1 = buf, *p2 = buf;#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 23, stdin), p1 == p2) ? EOF : *p1++)int rd() {reg char c = getchar(); reg int ret = 0;while (!isdigit(c)) c = getchar();do {ret = (ret << 3) + (ret << 1) + (c ^ 48); c = getchar();} while (isdigit(c));return ret;}char dig[18];void wt(int x) {reg int p = !x;while (x) dig[p++] = x % 10, x /= 10;while (p--) putchar(dig[p] + '0');}
}
namespace STL {	template <class T> inline void swap(T& a, T& b) { T t = a; a = b; b = t; }template <class T, class Cmp> inline void _qsort(T* data, int left, int right, Cmp q) {if (left >= right) return;T pivot = data[(left + right) / 2];swap(data[(left + right) / 2], data[left]);register int i = left + 1, j = right;while (i <= j) {while (i <= j && q(data[i], pivot)) i++;while (i <= j && q(pivot, data[j])) j--; if (i < j) swap(data[i], data[j]), i++, j--;else break;}swap(data[left], data[j]), _qsort(data, left, j - 1, q), _qsort(data, j + 1, right, q);}template <class T, class Cmp> inline void sort(T* begin, T* end, Cmp q) { _qsort(begin, 0, (int)(end - begin) - 1, q); }template <class T>class vector {private:T* data; // data valint end_1, end_2; // two end static constexpr int P = 100; // 阈值 void __resize(int __size) { // 内置 resize 扩展 end_2 空间T* __new_vec = new T[end_2 = __size];for (int ___i = 0; ___i < end_1; ___i++) __new_vec[___i] = data[___i]; // 拷贝delete data;data = __new_vec; }void __new(int __size) {__resize(__size + P);}public:vector<T>() {data = NULL; end_1 = end_2 = 0; __new(end_2);}vector<T>(int size, T start_val = T()) {__new(size); end_1 = size;for (int __II  = 0; __II < size; __II++) data[__II] = start_val;}void push_back(T q) {if (end_1 + 1 == end_2) __new(end_2); // 扩容data[end_1++] = q; }void pop_back() {end_1--;}bool empty() const {return end_1 == 0;}int size() const {return end_1;}T& operator[](unsigned long long q) {return data[q];}T& operator[](unsigned long long q) const {return data[q];}T* begin() {return data;}T* end() {return data + end_1;}void resize(int __n) {__new(__n);}};template <class T> struct greater {bool operator()(const T& a, const T& b) {return a > b;}};template <class T> struct less {bool operator()(const T& a, const T& b) {return a < b;}};
}
#define rd() fast_io::rd()
#define wt(Qj) fast_io::wt(Qj) // qjtemplate <int MAXN, int MAXM>
struct star_t {int head[MAXN], next[MAXM], to[MAXM], tot;star_t() : tot(0) {};void add(int x, int y) {next[++tot] = head[x]; head[x] = tot; to[tot] = y;}
};int n, m, v[N], k;
int new_v[N]; // 新的点的点权struct uf {int fa[N];void Init() {FOR(i, 0, N) fa[i] = i;}int find(int x) {return (fa[x] == x) ? x : fa[x] = find(fa[x]);}int merge(int x, int y) {return (x = find(x)) != (y = find(y)) ? fa[x] = y : 0;} 
};
star_t<N, M << 1> G;
namespace SolveLink {int s[N], s_tot = 0, color[N], tot, vis[N];star_t<N, M << 1> zheng, fan; // 正反图uf qwq;void calc() {function<int(int)> dfs1 = [&](int u) -> int {vis[u] = 1;for (int i = zheng.head[u]; i; i = zheng.next[i]) if (!vis[zheng.to[i]]) dfs1(zheng.to[i]);s[++s_tot] = u;};function<int(int)> dfs2 = [&](int u) -> int {color[u] = tot; new_v[tot] += v[u];for (int i = fan.head[u]; i; i = fan.next[i]) if (!color[fan.to[i]]) dfs2(fan.to[i]); 	};REP(i, 1, n) if (!vis[i]) dfs1(i);rREP(i, n, 1) if (!color[s[i]]) ++tot, dfs2(s[i]);}void main() {calc();REP(from, 1, n) for (int i = zheng.head[from]; i; i = zheng.next[i]) {int to = zheng.to[i];if (color[from] == color[to]) continue; G.add(color[from], color[to]);}}
}
namespace DAG_n {uf qwq;STL::vector<int> DAG[N]; // 计算 DAGint vis[N], tot = 0, dp[N] = {0}, Sort[N] = {0};int max(int a, int b) {return a > b ? a : b;}void main() {qwq.Init(); // 初始化并查集n = SolveLink::tot;REP(from, 1, n) for (int i = G.head[from]; i; i = G.next[i]) {int to = G.to[i];qwq.merge(from, to);}REP(i, 1, n) {if (!vis[qwq.find(i)]) vis[qwq.find(i)] = ++tot;int p = i;DAG[vis[qwq.find(i)]].push_back(p);}auto calc = [&](int idx) -> int { // 计算 DAGfor (int from : DAG[idx]) dp[from] = new_v[from];for (int from : DAG[idx]) for (int i = G.head[from]; i; i = G.next[i]) {int to = G.to[i];dp[to] = max(dp[to], dp[from] + new_v[to]);}int res = 0;for (int from : DAG[idx]) res = max(res, dp[from]);return res; };REP(i, 1, tot) Sort[i] = calc(i);STL::sort(Sort + 1, Sort + tot + 1, STL::greater<int>());int ans = 0; for (reg int i = 1; i <= tot && i <= k + 1; i++) ans += Sort[i];printf("%d", ans);}
}int main()
{//freopen("qwq.in", "r", stdin);freopen("azeroth.in", "r", stdin);freopen("azeroth.out", "w", stdout);n = rd(), m = rd();REP(i, 1, m) {int from = rd(), to = rd();if (from == to) continue;SolveLink::zheng.add(from, to), SolveLink::fan.add(to, from);}REP(i, 1, n) v[i] = rd();k = rd();SolveLink::main();DAG_n::main();
//	REP(i, 1, n) printf("%d=%d\n", i, SolveLink::color[i]);
//	for (int i = 1; i <= DAG_n::tot; i++) {
//		for (int u : DAG_n::DAG[i]) printf("%d ", u);
//		putchar('\n'); 
//	}
//	printf("Link=\n");
//	for (int i = 1; i <= n; i++) for (int j = G.head[i]; j; j = G.next[j]) {
//		printf("%d->%d\n", i, G.to[j]);
//	}return Pq;
}

向下看
向下看
向下看
向下看
向下看
向下看
向下看
向下看
向下看
向下看
向下看
向下看
向下看
向下看
向下看
向下看
向下看
向下看
向下看
向下看
向下看
向下看
向下看
向下看
向下看
向下看
向下看
向下看
向下看
向下看
向下看
向下看
向下看
向下看
向下看
向下看

你的代码是不是 RE 了?
你是不是已经注意到 Pq 的问题了?
但是代码还是AC不了?
因为我最讨厌ctj的人…

http://www.dtcms.com/a/511409.html

相关文章:

  • 基于 React + TypeScript + Fabric.js 构建一个封面生成器网站
  • 营销型电子商务网站品牌建设与推广思路
  • 更新网站 seo公司的管理方式与管理方法
  • BZV49-C22,115稳压二极管 NXP安世半导体 工业电源芯片 芯片解析
  • 职场发展—如何避雷垃圾公司
  • 【Linux篇】软链接vs硬链接:Linux文件系统中的两种引用机制
  • C++ list核心接口与实战技巧
  • 微服务框架
  • 网站模块结构图wordpress调用栏目名称
  • 算法学习记录03——二叉树学习笔记:从两道题看透后序位置的关键作用​
  • Rust高性能分布式任务调度系统开发实践:从设计到性能优化
  • go tools安装
  • 阿里云代理商:如何给阿里云配置网络ACL?
  • 阿里巴巴 Java 开发手册解读:DO、DTO、BO、AO、VO、Query 的区别与用法
  • 接口测试如何做
  • 记录日常日志
  • 【LeetCode_876_2.02】快慢指针在链表中的简单应用
  • LOOP套LOOP,双LOOP优化,效率提升近30倍
  • iOS 混淆实战 多工具组合完成 IPA 混淆、加固与工程化落地(iOS混淆|IPA加固|无源码混淆|Ipa Guard|Swift Shield)
  • 计算机毕设java中学生心理健康管理系统 中学生心理健康管理的Java平台解决方案 Java技术驱动的中学心理健康管理系统研发
  • 模重复平方计算法
  • 温州网站制作套餐.net网站开发是什么对象开发
  • Tuning——CC调试(适用高通)
  • 【AI智能体开发】什么是LLM?如何在本地搭建属于自己的Ai智能体?
  • Leetcode+Java+图论+并查集
  • 网站代备案流程图越秀网站建设推广
  • 网站 app 公众号先做哪个网站建设实践
  • SpringBoot常用内置工具类使用示例
  • Qt和ffmpeg结合打造gb28181推流/支持udp和tcp被动以及tcp主动三种方式
  • 设计模式-工厂模式:解耦对象创建的设计艺术