2025十一集训——Day3做题
A
题意:一个图,选择一个回答,\(k/2\) 的独立集或者不大于 \(k\) 的环。
考虑 \(k=n\) 如果是树直接黑白染色,否则必有环。
然后考虑出题人:“保证有解”,所以直接去一个 \(k\) 的联通块,按照 \(k=n\) 正常做即可……
水。
点击查看代码
#include <bits/stdc++.h>
#define dbg(x) cout << #x << '=' << x << endl
#define rep(i, l, r) for (int i = (l); i <= (r); i++)
#define frep(i, r, l) for (int i = (r); i >= (l); i--)
//#define int long long
using namespace std;
const int N = 2e5 + 10;
int n, m, k;
struct Edge {
int u, v;
} ed[N];
vector<int> e[N];
queue<int> q;
bool vis[N];
int newm;
vector<int> ee[N];
vector<int> col[2];
void Color(int u, int c, int f) {
col[c].push_back(u);
for (int v : ee[u]) {
if (v == f) continue;
Color(v, c ^ 1, u);
}
}
int top, sta[N], f[N];
vector<int> ans;
void Find(int u, int fa) {
sta[++top] = u, f[u] = 1;
for (int v : ee[u]) {
if (v == fa) continue;
if (f[v]) {
ans.push_back(v);
while (sta[top] != v) ans.push_back(sta[top--]);
cout << 2 << "\n" << ans.size() << "\n";
for (int x : ans) cout << x << " ";
exit(0);
}
Find(v, u);
}
top--;
}
void work()
{
cin >> n >> m >> k;
rep(i, 1, m) {
int u, v; cin >> u >> v;
ed[i] = {u, v};
e[u].push_back(v);
e[v].push_back(u);
}
int cnt = k - 1;
vis[1] = 1;
q.push(1);
while (cnt) {
int u = q.front(); q.pop();
for (int v : e[u]) {
if (!vis[v]) {
vis[v] = 1, cnt--; q.push(v);
if (cnt == 0) break;
}
}
}
rep(i, 1, m) {
if (vis[ed[i].u] && vis[ed[i].v]) {
newm++;
ee[ed[i].u].push_back(ed[i].v);
ee[ed[i].v].push_back(ed[i].u);
}
}
if (newm == k - 1) {
Color(1, 1, 0);
int res = (k + 1) / 2;
int ansc = 0;
if (col[0].size() < res) ansc = 1;
cout << 1 << "\n";
rep(i, 0, res - 1) cout << col[ansc][i] << " ";
return;
}
else Find(1, 0);
}
int main()
{
std::ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int T = 1, opinput = 0;
if (opinput) cin >> T;
while (T--) work();
return 0;
}
B
题意:\(m-n=20\),询问任意两点最短路。
\(m-n=20\) 一棵树多 21 条边,42 个点,跑出这 42 个到别的点最短路,直接枚举即可。
Cu水
点击查看代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 2e5 + 10;
const int P = 44;
const int INF = 1e18;
int n, m, Q;
struct Edge {
int u, v, w;
}ee[N];
int fa[N];
struct stu {
int to, nxt, w;
} t[N], g[N];
int cnt_t, head_t[N];
int cnt_g, head_g[N];
int dep[N], f[N][30], fd[N];
int use[N], tot, id[P], a[P][P];
int Find(int x) {return x == fa[x] ? x : fa[x] = Find(fa[x]);}
bool cmp(Edge a1, Edge a2) {return a1.w < a2.w;}
void Add_Edge_t(int u, int v, int d) {
t[++cnt_t] = {v, head_t[u], d};
head_t[u] = cnt_t;
}
void Add_Edge_g(int u, int v, int d) {
g[++cnt_g] = {v, head_g[u], d};
head_g[u] = cnt_g;
}
void Kruscal() {
for (int i = 1; i <= n; i++) fa[i] = i;
sort(ee + 1, ee + m + 1, cmp);
for (int i = 1; i <= m; i++) {
int u = ee[i].u, v = ee[i].v;
int fu = Find(u), fv = Find(v);
if (fu != fv) {
fa[fu] = fv;
Add_Edge_t(u, v, ee[i].w);
Add_Edge_t(v, u, ee[i].w);
}
else {
if (!use[u]) use[u] = ++tot, id[tot] = u;
if (!use[v]) use[v] = ++tot, id[tot] = v;
}
}
}
void Dfs(int u, int ff) {
dep[u] = dep[ff] + 1;
for (int i = 1; i <= 25; i++)
f[u][i] = f[f[u][i - 1]][i - 1];
for (int i = head_t[u]; i; i = t[i].nxt) {
int v = t[i].to;
if (v == ff) continue;
f[v][0] = u, fd[v] = fd[u] + t[i].w;
Dfs(v, u);
}
}
int Lca(int u, int v) {
if (dep[u] < dep[v]) swap(u, v);
for (int i = 25; i >= 0; i--) {
if (dep[f[u][i]] >= dep[v]) u = f[u][i];
}
if (u == v) return u;
for (int i = 25; i >= 0; i--) {
if (f[u][i] != f[v][i]) {
u = f[u][i], v = f[v][i];
}
}
return f[u][0];
}
int Query(int u, int v) {return fd[u] + fd[v] - 2 * fd[Lca(u, v)]; }
int vis[N], dis[P][N];
#define pi pair<int, int>
#define fi first
#define se second
#define mp make_pair
priority_queue<pi > q;
void Dijkstra(int p) {
while (!q.empty()) q.pop();
for (int i = 1; i <= n; i++) dis[p][i] = INF, vis[i] = 0;
dis[p][id[p]] = 0;
q.push(mp(0, id[p]));
while (!q.empty()) {
int u = q.top().se; q.pop();
if (vis[u]) continue;
vis[u] = 1;
for (int i = head_g[u]; i; i = g[i].nxt) {
int v = g[i].to, w = g[i].w;
if (dis[p][v] > dis[p][u] + w) {
dis[p][v] = dis[p][u] + w;
q.push(mp(-dis[p][v], v));
}
}
}
}
signed main() {
std::ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
cin >> n >> m;
for (int i = 1; i <= m; i++) {
cin >> ee[i].u >> ee[i].v >> ee[i].w;
Add_Edge_g(ee[i].u, ee[i].v, ee[i].w);
Add_Edge_g(ee[i].v, ee[i].u, ee[i].w);
}
Kruscal();
Dfs(1, 0);
for (int i = 1; i <= tot; i++) Dijkstra(i);
cin >> Q;
while (Q--) {
int u, v; cin >> u >> v;
int ans = Query(u, v);
for (int i = 1; i <= tot; i++) ans = min(ans, dis[i][u] + dis[i][v]);
cout << ans << "\n";
}
return 0;
}
C
题意,动态加边,所有环的异或和为一则加入,维护这个。
考虑有一棵树,那么加一条边可以直接树上查一条链的异或和判断。
然后考虑再来一条边,假设这条边合法,并且前面有一条边也合法,那么两条边之间的环为 \(1 xor 1 = 0\)!
所以一条边合法后在树上这条链打个标记,其他边,加入时只有没有标记才合法。
怎么建树?边离线下来并查集。
怎么查异或和?树上前缀和即可。
怎么标记?(可以树状数组但我写了个树剖)。
码量大,但思维难度似乎没有紫(大雾
不水……
点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int N = 3e5 + 10;
const int M = 5e5 + 10;
int n, q;
int cnt, head[N], nxt[N << 1], to[N << 1], w[N << 1];
struct stu {
int u, v, x;
} ed[M];
int ans[M];
int ff[N];
int Find(int x) {return x == ff[x] ? x : ff[x] = Find(ff[x]);}
void Add(int u, int v, int d) {
nxt[++cnt] = head[u];
to[cnt] = v, w[cnt] = d;
head[u] = cnt;
}
int dis[N], val[N], fa[N], siz[N], son[N], dep[N];
int tot, top[N], dfn[N], id[N];
void Dfs1(int u, int f) {
// cout << u << "\n";
fa[u] = f, siz[u] = 1;
dis[u] = dis[f] ^ val[u], dep[u] = dep[f] + 1;
for (int i = head[u]; i; i = nxt[i]) {
int v = to[i], d = w[i];
if (v == f) continue;
val[v] = d;
Dfs1(v, u);
siz[u] += siz[v];
if (siz[v] > siz[son[u]]) son[u] = v;
}
}
void Dfs2(int u, int tp) {
dfn[u] = ++tot, id[tot] = u;
top[u] = tp;
if (son[u])
Dfs2(son[u], tp);
for (int i = head[u]; i; i = nxt[i]) {
if (!dfn[to[i]]) Dfs2(to[i], to[i]);
}
}
int mx[N << 2], tag[N << 2];
#define ls x << 1
#define rs x << 1 | 1
#define lson ls, l, mid
#define rson rs, mid + 1, r
void PushUp(int x) {mx[x] = max(mx[ls], mx[rs]);}
void Change(int x, int k) {mx[x] = tag[x] = k;}
void PushDown(int x) {
if (tag[x]) {
Change(ls, tag[x]), Change(rs, tag[x]);
}
tag[x] = 0;
}
void Update(int x, int l, int r, int ql, int qr, int k) {
if (ql <= l && r <= qr) {Change(x, k); return;}
int mid = l + r >> 1; PushDown(x);
if (ql <= mid) Update(lson, ql, qr, k);
if (qr > mid) Update(rson, ql, qr, k);
PushUp(x);
}
int Query(int x, int l, int r, int ql, int qr) {
if (ql <= l && r <= qr) return mx[x];
int mid = l + r >> 1, res = 0; PushDown(x);
if (ql <= mid) res = max(res, Query(lson, ql, qr));
if (qr > mid) res = max(res, Query(rson, ql, qr));
return res;
}
void Update(int u, int v, int k) {
while (top[u] != top[v]) {
if (dep[top[u]] < dep[top[v]]) swap(u, v);
Update(1, 1, n, dfn[top[u]], dfn[u], k);
u = fa[top[u]];
}
if (dep[u] < dep[v]) swap(u, v);
if (dfn[u] != dfn[v])
Update(1, 1, n, dfn[v] + 1, dfn[u], k);
}
int Query(int u, int v) {
int res = 0;
while (top[u] != top[v]) {
if (dep[top[u]] < dep[top[v]]) swap(u, v);
res = max(res, Query(1, 1, n, dfn[top[u]], dfn[u]));
u = fa[top[u]];
}
if (dep[u] < dep[v]) swap(u, v);
if (dfn[u] != dfn[v])
res = max(res, Query(1, 1, n, dfn[v] + 1, dfn[u]));
return res;
}
int Dis(int u, int v) {return dis[u] ^ dis[v];}
int main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
cin >> n >> q;
for (int i = 1; i <= n; i++) ff[i] = i;
for (int i = 1; i <= q; i++) {
int u, v, x; cin >> u >> v >> x;
ed[i] = (stu){u, v, x};
int fu = Find(u), fv = Find(v);
if (fu != fv) {
ff[fu] = fv, ans[i] = 1;
Add(u, v, x), Add(v, u, x);
}
}
for (int i = 1; i <= n; i++) {
if (i == ff[i]) Dfs1(i, 0), Dfs2(i, i);
}
for (int i = 1; i <= q; i++) {
if (ans[i]) continue;
int u = ed[i].u, v = ed[i].v;
if (((Dis(u, v) ^ ed[i].x) == 1) && Query(u, v) == 0) {
ans[i] = 1; Update(u, v, 1);
}
}
for (int i = 1; i <= q; i++)
cout << (ans[i] ? "YES" : "NO") << "\n";
return 0;
}
本文来自博客园,作者:zhangxiao666,转载请注明原文链接:https://www.cnblogs.com/zhangxiao666qwq/p/19126439

浙公网安备 33010602011771号