2025十一集训——Day3做题

A

vjudge

CF

题意:一个图,选择一个回答,\(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

vjudge

CF

题意:\(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

vjudge

CF

题意,动态加边,所有环的异或和为一则加入,维护这个。

考虑有一棵树,那么加一条边可以直接树上查一条链的异或和判断。

然后考虑再来一条边,假设这条边合法,并且前面有一条边也合法,那么两条边之间的环为 \(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;
}
posted @ 2025-10-05 11:54  zhangxiao666  阅读(6)  评论(0)    收藏  举报