Codeforces Round 1044 (Div. 2) (E, F)

https://codeforces.com/contest/2133

E

交互题感觉只要看给出的询问次数就能推测出做法。
显然至少每个点都要进行一次操作1,最多也就少问一个点可以忽略不计,所以剩下的次数就是用来进行操作2的。也就是说每四个点要进行操作2。手玩小样例,菊花图,二叉树,链,可以发现只要把siz大于4的模块直接截断,最后剩下的连通块大小都不超过3,也就是都是一条链,一条链的情况是直接询问得出的。(题解写法有点类似树链剖分,不过本题思维难度不高,主要在于实现难度,每四个点截断非常好写)

采用给树染色的方法,能很容易分类讨论一个连通块的三种情况(截断点,链端点为lca或者链端点不为lca)。又因为一个点有效儿子不超过2个,记录一下就很好写了。

#include<bits/stdc++.h>
using namespace std;
#define lowbit(x) (x & (-x))
#define ls(x) (x << 1)
#define int long long
#define endl '\n'
#define rs(x) (x << 1 | 1)
const int N = 2e5 + 7, MOD = 998244353;
int mul(int x, int y) {return 1ll * x * y % MOD;}
int qpow(int x, int y) {
    int res = 1; while(y) {
        if (y & 1) res = mul(res, x);
        x = mul(x, x); y >>= 1;} return res;
}
vector<int> E[N];
vector<pair<int, int>> ans;
int n, col[N], son1[N], son2[N];
void init() {
    ans.clear();
    for (int i = 1; i <= n; i++) 
        son1[i] = son2[i] = col[i] = 0, E[i].clear();
}
void dfs(int x, int fa) {
    int cnt = 0;
    for (int v : E[x]) {
        if (v == fa) continue;
        dfs(v, x);
        if (col[v] == 1) {
            cnt++;
            if (!son1[x]) son1[x] = v;
            else son2[x] = v;    
        }
        else if (col[v] == 2) cnt += 10;
    }   
    if (cnt > 2) col[x] = 3;
    else if (cnt == 2) col[x] = 2;
    else col[x] = 1;
    // cout << x << ' ' << col[x] << " ???" << endl;
}
void dfs0(int x, int fa) {
    if (son1[x]) dfs0(son1[x], x);
    ans.push_back({1, x});
    col[x] = 3;
}
void dfs3(int x, int fa) {
    int p = 0;
    if (col[x] == 1) {
        ans.push_back({1, x});
        if (son1[x]) dfs3(son1[x], x), p = son1[x];
    }
    for (int i : E[x]) {
        if (i == p || i == fa) continue;
        dfs3(i, x);
    }
}
void solve() {
    cin >> n;
    init();
    for (int i = 1; i < n; i++) {
        int u, v; cin >> u >> v;
        E[u].push_back(v); E[v].push_back(u);
    }
    dfs(1, 0);
    for (int i = 1; i <= n; i++) {
        if (col[i] == 3) ans.push_back({1, i}), ans.push_back({2, i});
    }
    for (int i = 1; i <= n; i++) {
        if (col[i] == 2) {
            dfs0(son1[i], i);
            ans.push_back({1, i});
            int cur = son2[i];
            while(cur) {
                col[cur] = 3;
                ans.push_back({1, cur});
                cur = son1[cur];
            }
        }
    }
    dfs3(1, 0);
    cout << ans.size() << endl;
    for (auto i : ans) {
        cout << i.first << ' ' << i.second << endl;
    }
}
signed main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr); cout.tie(nullptr);
    int T; 
    cin >> T;
    while(T--) solve();
}

F

线段树优化DP

posted @ 2025-08-27 21:03  lyrrr  阅读(13)  评论(0)    收藏  举报