P8819 [CSP-S 2022] 星战 (很厉害的随机化想法)
本题 trick : 随机化,求出度转化成入度
简化下题意
有n个点 m条单向边 每条边有激活和失活两种状态,一共有4中操作
1.失活一条 u->v 的边
2.失活终点是 v 的边
3.激活 u->v 的边
4.激活终点是 v 的边
问你每次修改后 每个点的出度是否都为 1.
50分的做法就是暴力修改,对于 1操作和3操作 都是 可以 o(1)解决,对于 2操作和 4操作需要 o(n)。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pir;
const int N = 5e5 + 5;
int out[N];
std::vector<int> g[N];
map<int, int>mp[N];
void solve()
{
int n, m;
cin >> n >> m;
int cnt = 0;
for(int i = 1; i <= m; i++)
{
int u, v;
cin >> u >> v;
g[v].push_back(u);
mp[v][u] = 1;
out[u]++;
if(out[u] == 1)cnt++;
else if(out[u] == 2)cnt--;
}
int q;
cin >> q;
while(q--)
{
int op, u, v;
cin >> op;
if(op == 1)
{
cin >> u >> v;
mp[v][u] = 0;
out[u]--;
if(out[u] == 0)cnt--;
else if(out[u] == 1)cnt++;
}
else if(op == 2)
{
cin >> u;
for(int v : g[u])
{
if(mp[u][v])
{
out[v]--;
if(out[v] == 0)cnt--;
else if(out[v] == 1)cnt++;
mp[u][v] = 0;
}
}
}
else if(op == 3)
{
cin >> u >> v;
mp[v][u] = 1;
out[u]++;
if(out[u] == 1)cnt++;
else if(out[u] == 2)cnt--;
}
else
{
cin >> u;
for(int v : g[u])
{
if(mp[u][v] == 0)
{
out[v]++;
if(out[v] == 1)cnt++;
else if(out[v] == 2)cnt--;
mp[u][v] = 1;
}
}
}
if(cnt == n)cout << "YES\n";
else cout << "NO\n";
}
}
int main()
{
// freopen("data.in", "r", stdin);
// freopen("data.out", "w", stdout);
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
solve();
}
一个比较牛逼的想法就是不维护出度,改成维护入度。
发现如果维护入度,那么对于4个操作都复杂度都是 o(1).
当符合每个点的出度都为 1 时,那么出度 总和就是 n,入度总和也是 n。
入度为 n 只是符合题目的一个 必要条件。
本题就是使用随机化使得这个必要条件无限接近充分必要条件。
具体做法是 对每个点i赋一个随机的权值 w[i].
对于每个点u的入度和就是
现在这个条件
就是满足 题目要求的一个 必要条件,但是呢因为随机化,就会无限的接近充分必要条件。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pir;
const int N = 5e5 + 5;
void solve()
{
int n, m;
cin >> n >> m;
std::mt19937 rnd(time(0));
std::vector<ll> w(n + 1);
ll sum = 0;
for(int i = 1; i <= n; i++)
{
w[i] = rnd();
sum += w[i];
}
std::vector<ll> r(n + 1), g(n + 1);
ll tot = 0;
for(int i = 1; i <= m; i++)
{
int u, v;
cin >> u >> v;
r[v] += w[u];
tot += w[u];
}
for(int i = 1; i <= n; i++)g[i] = r[i];
int q;
cin >> q;
while(q--)
{
int op, u, v;
cin >> op;
if(op == 1)
{
cin >> u >> v;
r[v] -= w[u];
tot -= w[u];
}
else if(op == 2)
{
cin >> u;
tot -= r[u];
r[u] = 0;
}
else if(op == 3)
{
cin >> u >> v;
r[v] += w[u];
tot += w[u];
}
else
{
cin >> u;
tot += g[u] - r[u];
r[u] = g[u];
}
if(tot == sum)cout << "YES\n";
else cout << "NO\n";
}
}
int main()
{
// freopen("data.in", "r", stdin);
// freopen("data.out", "w", stdout);
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
solve();
}
/*
*/
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)