2017-2018 ACM-ICPC Southeastern European Regional Programming Contest (SEERC 2017)

 

2017-2018 ACM-ICPC Southeastern European Regional Programming Contest (SEERC 2017)

全靠 wxh的博客 补完这套。wxhtxdy!

 

[A - Concerts]

$f[i][k]$ 表示在第 $i$ 个位置刚好匹配了 $k$ 个字符。转移方程 $$ f[i][k] = \sum_{i - j > h[s[k - 1]]} f[j][k - 1] $$

前缀和优化加滚动就行了。

好像可以直接用 $f[i][k]$ 表示前缀和,就没这么多事了。

#include <bits/stdc++.h>

const int N = 1e5 + 7;
const int MOD = 1e9 + 7;

int dp[2][N], sum[2][N], h[N];
char s[N], t[N];

void M(int &a) {
    if (a >= MOD) a -= MOD;
}

int main() {
    freopen("in.txt", "r", stdin);
    int k, n;
    scanf("%d%d", &k, &n);
    for (int i = 0; i < 26; i++)
        scanf("%d", h + i);
    scanf("%s%s", t + 1, s + 1);
    for (int i = 1; i <= n; i++) {
        if (s[i] == t[1])
            dp[1][i] = 1;
        sum[1][i] =  sum[1][i - 1] + dp[1][i];
    }
    for (int j = 2; j <= k; j++) {
        int cur = j & 1, pre = cur ^ 1;
        memset(dp[cur], 0, sizeof(dp[cur]));
        memset(sum[cur], 0, sizeof(sum[cur]));
        for (int i = 1; i <= n; i++) {
            if (s[i] == t[j]) {
                int where = i - h[t[j - 1] - 'A'] - 1;
                if (where > 0)
                    M(dp[cur][i] += sum[pre][where]);
            }
            //if (i == 2) printf("%d\n", dp[cur][i]);
            M(sum[cur][i] += sum[cur][i - 1]);
            M(sum[cur][i] += dp[cur][i]);
        }
    }
    printf("%d\n", sum[k & 1][n]);
    return 0;
}
View Code

 

[B - Bricks]

操作顺序对答案无影响,从前往后DP即可。

枚举空位进行DP,$f[i]$ 表示 $i$ 之前已经放好,并且产生了 $i - 1 - cnt[i - 1]$ 个空位的方案数, $g[i]$ 则表示产生了 $i$ 个空位的方案数。

#include <bits/stdc++.h>

const int N = 1e6 + 7;
const int MOD = 1e9 + 7;
int f[N], g[N], cnt[N];

void M(int &a) {
    if (a >= MOD) a -= MOD;
}

int main() {
    int n, m;
    scanf("%d%d", &n, &m);
    n++;
    while (m--) {
        int x;
        scanf("%d", &x);
        cnt[x]++;
    }
    for (int i = 1; i <= n; i++)
        cnt[i] += cnt[i - 1];
    g[0] = 1;
    for (int i = 1; i <= n; i++) {
        if (cnt[i] == cnt[i - 1]) {
            if (i - 1 - cnt[i - 1] >= 0)
                f[i] = g[i - 1 - cnt[i - 1]];
            if (i - cnt[i] >= 0)
                M(g[i - cnt[i]] += f[i]);
        }
    }
    printf("%d\n", f[n]);
    return 0;
}
View Code

 

[C - Christmas Tree

对于每种颜色能求出其极长链,也就是每次操作两端的端点。

然后操作之间相当于一个拓扑序,对每一种颜色向其链上不同颜色的点连边,拓扑排序即可。

连边需要用倍增优化,就是一次连边只需要连 $logn$ 条边。

#include <bits/stdc++.h>
#define pii pair<int, int>
#define fi first
#define se second

const int N = 1e5 + 7;
const int M = 17;
const int S = N * 20;

int n, m, color[N], dep[N], degree[S], fa[N][M], id[N][M];
std::vector<int> vec[N], col[N], to[S];

void dfs(int u, int pre = 0) {
    dep[u] = dep[pre] + 1;
    fa[u][0] = pre;
    for (int i = 1; i < M; i++)
        fa[u][i] = fa[fa[u][i - 1]][i - 1];
    for (int v: vec[u]) 
        if (v != pre)
            dfs(v, u);
}

int jump(int u, int d) {
    for (int i = 0; i < M; i++)
        if (d >> i & 1)
            u = fa[u][i];
    return u;
}

int Lca(int u, int v) {
    if (dep[u] < dep[v]) std::swap(u, v);
    u = jump(u, dep[u] - dep[v]);
    if (u == v) return u;
    for (int i = M - 1; ~i; i--)
        if (fa[u][i] != fa[v][i])
            u = fa[u][i], v = fa[v][i];
    return fa[u][0];
}

int dist(int u, int v) {
    return dep[u] + dep[v] - 2 * dep[Lca(u, v)];
}

int find(int u, int v, int z, int d) {
    if (d <= dep[u] - dep[z])
        return jump(u, d);
    return jump(v, dep[u] + dep[v] - 2 * dep[z] - d);
}

void addedge(int color, int u, int v) {
    if (dep[u] < dep[v]) std::swap(u, v);
    int dif = dep[u] - dep[v];
    for (int i = 0; i < M; i++)
        if (dif >> i & 1) {
            to[color].push_back(id[u][i]);
            u = fa[u][i];
        }
    if (u == v) {
        to[color].push_back(id[u][0]);
        return;
    }
    for (int i = M - 1; ~i; i--) 
        if (fa[u][i] != fa[v][i]) {
            to[color].push_back(id[u][i]);
            to[color].push_back(id[v][i]);
            u = fa[u][i];
            v = fa[v][i];
        }
    to[color].push_back(id[u][0]);
    to[color].push_back(id[v][0]);
    to[color].push_back(id[fa[u][0]][0]);
}

int X[N], Y[N];

int main() {
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++) {
        scanf("%d", color + i);
        col[color[i]].push_back(i);
    }
    for (int i = 1; i < n; i++) {
        int u, v;
        scanf("%d%d", &u, &v);
        vec[u].push_back(v);
        vec[v].push_back(u);
    }
    dfs(1);
    int tol = m;
    for (int i = 0; i < M; i++)
        for (int j = 1; j <= n; j++)
            id[j][i] = ++tol;
    for (int i = 1; i <= n; i++)
        to[id[i][0]].push_back(color[i]);
    for (int i = 1; i < M; i++)
        for (int j = 1; j <= n; j++)
            if (fa[j][i - 1]) {
                to[id[j][i]].push_back(id[j][i - 1]);
                to[id[j][i]].push_back(id[fa[j][i - 1]][i - 1]);
            }
    for (int i = 1; i <= m; i++) {
        if (col[i].empty()) {
            printf("%d 1 1\n", i);
            continue;
        }
        int x = col[i][0], y = col[i][0], d = 0;
        for (int j = 1; j < col[i].size(); j++) {
            int z = col[i][j], dd;
            dd = dist(x, z);
            int flag = 0;
            if (dd > d) {
                d = dd;
                flag = 1;
            }
            dd = dist(y, z);
            if (dd > d) {
                d = dd;
                flag = 2;
            }
            if (flag == 1) {
                y = z;
            } else if (flag == 2) {
                x = z;
            }
        }
        X[i] = x; Y[i] = y;
        int z = Lca(x, y);
        std::vector<std::pii> all;
        for (int p: col[i]) 
            all.push_back(std::pii(dist(x, p), p));
        std::sort(all.begin(), all.end());
        for (int j = 1; j < all.size(); j++) 
            if (all[j].fi != all[j - 1].fi + 1) {
                int u = find(x, y, z, all[j].fi - 1), v = find(x, y, z, all[j - 1].fi + 1);
                addedge(i, u, v);
            }
    }
    for (int i = 1; i <= tol; i++)
        for (auto v: to[i])
            degree[v]++;
    std::queue<int> que;
    for (int i = 1; i <= tol; i++)
        if (!degree[i])
            que.push(i);
    while (!que.empty()) {
        int u = que.front(); que.pop();
        if (u <= m && !col[u].empty()) 
            printf("%d %d %d\n", u, X[u], Y[u]);
        for (int v: to[u]) 
            if (!--degree[v])
                que.push(v);
    }
    return 0;
}
View Code

 

[D - Harry Potter and The Vector Spell]

并查集合并每一列中两个 $1$,不在同一个集合里则对答案贡献为 $1$

#include <bits/stdc++.h>

const int N = 1e5 + 7;

int fa[N];

int getfa(int x) {
    return x == fa[x] ? x : fa[x] = getfa(fa[x]);
}

std::vector<int> G[N];

int main() {
    int n, m;
    scanf("%d%d", &m, &n);
    for (int i = 1; i <= m; i++) {
        fa[i] = i;
        int k;
        scanf("%d", &k);
        while (k--) {
            int u;
            scanf("%d", &u);
            G[u].push_back(i);
        }
    }
    int ans = 0;
    for (int i = 1; i <= n; i++) {
        if (G[i].size() == 0) continue;
        if (G[i].size() == 1) { ans++; continue; }
        int u = G[i][0], v = G[i][1];
        u = getfa(u);
        v = getfa(v);
        if (u != v) {
            ans++;
            fa[u] = v;
        }
    }
    printf("%d\n", ans);
}
View Code

 

[E - Looping Playlist

预处理下每个 major scale 以及其子集。

然后枚举开头和结尾拼起来的是哪个 major scale,中间段再贪心即可。

#include <bits/stdc++.h>

std::map<std::string, int> mp;
const int N = 1e7 + 7;
int a[N];
bool flag[N];
const int offset[8] = {0, 2, 4, 5, 7, 9, 11, 12};

void print(int x) {
    for (int i = 13; ~i; i--)
        printf("%d", x >> i & 1);
    puts("");
}

int main() {
    std::ios::sync_with_stdio(false); std::cin.tie(0);
    mp["Do"] = 0; mp["Do#"] = 1;
    mp["Re"] = 2; mp["Re#"] = 3;
    mp["Mi"] = 4; mp["Fa"] = 5;
    mp["Fa#"] = 6; mp["Sol"] = 7;
    mp["Sol#"] = 8; mp["La"] = 9;
    mp["La#"] = 10; mp["Si"] = 11;
    for (int i = 0; i < 12; i++) {
        int s = 0;
        for (int j = 0; j < 8; j++)
            s |= 1 << ((i + offset[j]) % 12);
        flag[s] = 1;
    }
    for (int i = 1; i < 1 << 12; i++) 
        for (int j = i; j; j = (j - 1) & i)
        flag[j] |= flag[i];
    int n;
    std::cin >> n;
    for (int i = 1; i <= n; i++) {
        std::string str;
        std::cin >> str;
        a[i] = mp[str];
    }
    assert(!flag[(1 << 12) - 1]);
    int ans = n;
    for (int i = 0; i < 12; i++) {
        int s = 0;
        for (int j = 0; j < 8; j++)
            s |= 1 << ((i + offset[j]) % 12);
        int l = 1, r = n;
        while (l <= n && (s >> a[l] & 1))
            l++;
        while (r && (s >> a[r] & 1))
            r--;
        int cur = 1;
        s = (1 << 12) - 1;
        for (int j = l; j <= r; j++) {
            if (!flag[s | (1 << a[j])]) {
                cur++;
                s = 1 << a[j];
            } else {
                s |= 1 << a[j];
            }
        }
        ans = std::min(ans, cur);
    }
    std::cout << ans << '\n';
    return 0;
}
View Code

 

[F - Binary Transformations]

贪心地考虑,先把不匹配的 $1$ 从大到小消掉,再把不匹配的 $0$ 从小到大加上。但是如果存在一些匹配了的 $1$ 它们的花费特别大,就不是最优的。

那么就枚举多消去几个已经匹配了的 $1$,这部分肯定也是从大到小优。

用multiset维护即可。

#include <bits/stdc++.h>
#define ll long long

const int N = 1e4 + 7;

std::multiset<ll, std::greater<ll> > st1;
std::multiset<ll> st2;
std::vector<ll> vec;
int n;
ll c[N];
ll sum;
char a[N], b[N];

ll solve(int cnt) {
    ll ans = 0;
    ll s = sum;
    if (cnt)
        st1.insert(vec[cnt - 1]), st2.insert(vec[cnt - 1]);
    for (auto it: st1) {
        s -= it;
        ans += s;
    }
    for (auto it: st2) {
        s += it;
        ans += s;
    }
    return ans;
}

int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; i++)
        scanf("%lld", c + i);
    scanf("%s", a + 1);
    scanf("%s", b + 1);
    for (int i = 1; i <= n; i++) {
        if (a[i] != b[i]) {
            if (a[i] == '1') st1.insert(c[i]);
            else st2.insert(c[i]);
        } else {
            if (a[i] == '1') vec.push_back(c[i]);
        }
        if (a[i] == '1') sum += c[i];
    }
    std::sort(vec.begin(), vec.end(), std::greater<ll>());
    ll ans = 1e18;
    for (int i = 0; i <= vec.size(); i++)
        ans = std::min(ans, solve(i));
    printf("%lld\n", ans);
    return 0;
}
View Code

 

[G - Robots]

#include <bits/stdc++.h>

#define ll long long

const int N = 1e4 + 7;

struct In {
    ll a, t;
    bool operator < (const In &rhs) const {
        return a > rhs.a;
    }
} in[N];

int main() {
    int n;
    scanf("%d", &n);
    for (int i = 0; i < n; i++)
        scanf("%lld%lld", &in[i].a, &in[i].t);
    ll v = 0;
    double ans1 = 0;
    for (int i = 0; i < n; i++) {
        ans1 += v * in[i].t + 0.5 * in[i].a * in[i].t * in[i].t;
        v += in[i].a * in[i].t;
    }
    std::sort(in, in + n);
    v = 0;
    double ans = 0;
    for (int i = 0; i < n; i++) {
        ans += v * in[i].t + 0.5 * in[i].a * in[i].t * in[i].t;
        v += in[i].a * in[i].t;
    }
    printf("%.1f\n", ans - ans1);
    return 0;
}
View Code

 

[H - Cat and Mouse]

如果老鼠和猫现在在一条边的两个端点 $(u, v)$ 上,老鼠先走一步到 $w$。

1. 如果老鼠走第二步不回到 $u$,那么猫肯定得跟过去。

2. 如果老鼠第二步走回 $u$,那么猫可以先不走,让老鼠回到 $u$,它再走到 $u$,老鼠走一步到 $w$,猫再跟上,老鼠走一步到 $u$,猫不动,这样就是猫用了 $4$ 步把老鼠在 $u$ 的后继节点 $w$ 给堵住了。

这样的话对每一条边 $(u, v)$ 设为 $(mouse, cat)$。预处理出后继状态以及到终态的最短路。

然后枚举一下老鼠走了几步到达和猫相邻的状态,通过节点深度判断猫是否能到这个状态,可以的话更新答案。

#include <bits/stdc++.h>

const int N = 1e5 + 7;
const int M = N * 4;
const int INF = 0x3f3f3f3f;

#define pii pair<int, int>
#define fi first
#define se second

std::vector<std::pii> edge, to[M];
std::vector<int> vec[N], temp[M];
int dis[N], dep[N];
int n, mouse;

void dfs(int u, int fa) {
    for (int v: vec[u]) {
        if (v == fa) continue;
        dep[v] = dep[u] + 1;
        dfs(v, u);
    }
}

int getid(int x, int y) {
    return lower_bound(edge.begin(), edge.end(), std::pii(x, y)) - edge.begin();
}

int getnext(int u, int no) {
    for (int v: vec[u])
        if (v != no) return v;
    return -1;
}

int main() {
    int T;
    scanf("%d", &T);
    while (T--) {
        scanf("%d%d", &n, &mouse);
        mouse--;
        for (int i = 0; i < n; i++)
            vec[i].clear(), dep[i] = 0;
        edge.clear();
        for (int i = 1; i < n; i++) {
            int u, v;
            scanf("%d%d", &u, &v);
            u--; v--;
            vec[u].push_back(v);
            vec[v].push_back(u);
            edge.push_back(std::pii(u, v));
            edge.push_back(std::pii(v, u));
        }
        std::sort(edge.begin(), edge.end());
        for (int i = 0; i < n; i++)
            std::reverse(vec[i].begin(), vec[i].end());
        if (!~getnext(mouse, -1)) {
            puts("0");
            continue;
        }
        dfs(0, -1);
        for (int i = 0; i < n * 4; i++)
            temp[i].clear();
        for (int i = 0; i < edge.size(); i++)
            dis[i] = INF, to[i].clear();
        for (int i = 0; i < edge.size(); i++) {
            int u = edge[i].fi, v = edge[i].se;
            int w = getnext(u, v);
            if (!~w) {
                dis[i] = 0;
                temp[0].push_back(i);
            } else {
                to[getid(w, u)].push_back(std::pii(i, 1));
                if (getnext(w, -1) == u)
                    to[getid(u, w)].push_back(std::pii(i, 4));
            }
        }
        for (int i = 0; i < n * 4; i++) 
            for (int j: temp[i]) 
                if (dis[j] == i)
                    for (auto p: to[j])
                        if (dis[p.fi] > i + p.se) {
                            dis[p.fi] = i + p.se;
                            temp[dis[p.fi]].push_back(p.fi);
                        }
        int ans = INF, cur = mouse;
        for (int i = 0; i < n; i++) {
            int ne = getnext(cur, i ? -1 : 0);
            if (dep[ne] < i || (dep[ne] == i && dep[cur] != i - 1))
                ans = std::min(ans, i + dis[getid(cur, ne)]);
            cur = ne;
        }
        printf("%d\n", ans);
    }
    return 0;
}
View Code

 

[I - Tetris]

虽说总的状态数是 1 << 30 个,但真正的状态数不会很多,很多状态都无法达到。

所以直接记忆化搜索(抄了wxh的代码,对于位运算部分的处理tql)

#include <bits/stdc++.h>

const int N = 55;

const char s[3][N] = {
    "010111110011110010010010011001",
    "111100011010010010111011111111",
    "010100001110011111011110110110"
};

std::unordered_map<int, int> mem[N], vis[N];
int n, a[N];

int go(int state, int type, int rotate) {
    if (state >> 21) return -1;
    char b[3][3];
    if (!rotate) {
        for (int i = 0; i < 3; ++i)
            for (int j = 0; j < 3; ++j)
                b[i][j] = s[i][j + type * 3];
    } else if (rotate == 1) {
        for (int i = 0; i < 3; ++i)
            for (int j = 0; j < 3; ++j)
                b[i][j] = s[j][2 - i + type * 3];
    } else if (rotate == 2) {
        for (int i = 0; i < 3; ++i)
            for (int j = 0; j < 3; ++j)
                b[i][j] = s[2 - i][2 - j + type * 3];
    } else {
        for (int i = 0; i < 3; ++i)
            for (int j = 0; j < 3; ++j)
                b[i][j] = s[2 - j][i + type * 3];
    }
    int p = 7;
    for (int i = 6; ~i; --i) {
        bool flag = false;
        for (int j = 0; j < 3; ++j)
            for (int k = 0; k < 3; ++k)
                if (b[j][k] == '1' && (state >> (i + j) * 3 + k & 1))
                    flag = true;
        if (flag) break;
        p = i;
    }
    int new_state = state;
    for (int i = 0; i < 3; ++i)
        for (int j = 0; j < 3; ++j)
            if (b[i][j] == '1')
                new_state |= 1 << (i + p) * 3 + j;
    for (int i = 0; i < 10; ++i)
        while ((new_state >> i * 3 & 7) == 7)
            new_state = (new_state & (1 << 3 * i) - 1) | (new_state >> (i + 1) * 3 << i * 3);
    return new_state;
}

int dfs(int state, int cur) {
    if (vis[cur][state] == 1) return -1;
    if (vis[cur][state] == 2) return mem[cur][state];
    vis[cur][state] = 1;
    int ans = 0;
    for (int i = 0; i < 4; i++) {
        int ne = go(state, a[cur], i);
        if (~ne) {
            int val = dfs(ne, (cur + 1) % n);
            if (!~val) return -1;
            ans = std::max(ans, val + 1);
        }
    }
    vis[cur][state] = 2;
    mem[cur][state] = ans;
    return ans;
}

int main() {
    scanf("%d", &n);
    for (int i = 0; i < n; i++)
        scanf("%d", a + i);
    printf("%d\n", dfs(0, 0));
    return 0;
}
View Code

 

[J - Cunning Friends]

三个人的nim...

如果全是 $1$,那么 $n \equiv 0$  (mod $3$)时必输,否则必胜。

如果只有一个不是 $1$,如果  $n \equiv 0$  (mod $3$),第一个人把 非 $1$ 那堆取出 $1$ 就必胜,否则把那一堆取光。

如果有两个不是 $1$,且至少有一个 $2$ 并且 $1$ 的个数不是 $3$ 的倍数,第一个人都可以把一堆取光或者取剩下 $1$ 使得自己赢,否则必败,另外两个人都可以让 $n \equiv 0$  (mod $3$)

如果大于两个,另外两个人的操作空间比第一个人大,就可以让第一个人必败了。

#include <bits/stdc++.h>

int main() {
    int n;
    int cnt1 = 0, cnt2 = 0;
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) {
        int x;
        scanf("%d", &x);
        if (x == 1) cnt1++;
        else if (x == 2) cnt2++;
    }
    if (cnt1 == n) puts(n % 3 == 0 ? "Lose" : "Win");
    else if (cnt1 == n - 1) puts("Win");
    else if (cnt1 == n - 2) puts((cnt2 && cnt1 % 3 != 0) ? "Win" : "Lose");
    else puts("Lose");
}
View Code

 

[K - Escape Room]

对于 $n$ 它的最长上升子序列肯定是 $1$,对于 $n-1$,如果它在 $n$ 后面那么肯定是 $1$,如果在 $n$ 前面那么肯定是 $2$,但是放后面会使得字典序更小。

那么就按最长上升子序列的值排个序。值小的放大的数,同权值的,越靠前面的放越大的数才符合最长上升子序列的值。

#include <bits/stdc++.h>

const int N = 1e5 + 7;

struct In {
    int pos, val;
    bool operator < (const In &rhs) const {
        if (val == rhs.val) return pos < rhs.pos;
        return val < rhs.val;
    }
} in[N];

int ans[N];

int main() {
    int n;
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) {
        scanf("%d", &in[i].val);
        in[i].pos = i;
    }
    std::sort(in + 1, in + 1 + n);
    for (int i = 1; i <= n; i++)
        ans[in[i].pos] = n - i + 1;
    for (int i = 1; i <= n; i++)
        printf("%d%c", ans[i], " \n"[i == n]);
    return 0;
}
View Code

 

[L - Divide and Conquer]

总边数是 $4(n-1)$,至少存在一个点的度数不超过 $3$,那么答案肯定不超过 $3$,并且有一棵树的只割去一条边。

枚举 $A$ 树中每一条边作为割边,在 $B$ 树中这条边连接的两个端点在 $A$ 树中不在一个连通块中,那么这条边需要割掉。

树上启发式合并解决。

#include <bits/stdc++.h>
#define pii pair<int, int>

const int N = 1e5 + 7;

struct Tree {
    std::vector<int> G[N];
    int son[N], sz[N];
    inline void add(int u, int v) {
        G[u].push_back(v);
        G[v].push_back(u);
    }
    void dfs(int u, int fa) {
        sz[u] = 1;
        for (auto v: G[u]) {
            if (v == fa) continue;
            dfs(v, u);
            sz[u] += sz[v];
            if (sz[son[u]] < sz[v]) son[u] = v;
        }
    }
} a, b;

bool skip[N], color[N];
int cur, n;

void cal(int u, const Tree &a) {
    color[u] ^= 1;
    for (auto v: a.G[u])
        if (color[v] != color[u]) cur++;
        else cur--;
}

void edt(int u, int fa, const Tree &a, const Tree &b) {
    cal(u, b);
    for (auto v: a.G[u])
        if (v != fa && !skip[v])
            edt(v, u, a, b);
}

void dfs(int u, int fa, bool keep, const Tree &a, const Tree &b, std::pii &ans) {
    for (auto v: a.G[u]) 
        if (v != fa && v != a.son[u])
            dfs(v, u, 0, a, b, ans);
    if (a.son[u])
        dfs(a.son[u], u, 1, a, b, ans), skip[a.son[u]] = 1;
    edt(u, fa, a, b);
    if (fa) {
        if (cur < ans.first) ans = std::pii(cur, 0);
        if (ans.first == cur) ans.second++;
    }
    if (a.son[u]) skip[a.son[u]] = 0;
    if (!keep)
        edt(u, fa, a, b);
}

std::pii solve(Tree &a, Tree &b) {
    a.dfs(1, 0);
    std::pii ans = std::pii(n, 0);
    dfs(1, 0, 0, a, b, ans);
    ans.first++;
    return ans;
}

int main() {
    scanf("%d", &n);
    for (int i = 1; i < n; i++) {
        int u, v;
        scanf("%d%d", &u, &v);
        a.add(u, v);
    }
    for (int i = 1; i < n; i++) {
        int u, v;
        scanf("%d%d", &u, &v);
        b.add(u, v);
    }
    auto ans = solve(a, b);
    if (ans.first == 2) 
        return 0 * printf("%d %d\n", 2, ans.second);
    cur = 0;
    auto res = solve(b, a);
    cur = 0;
    if (ans.first == 3) cur += ans.second;
    if (res.first == 3) cur += res.second;
    printf("%d %d\n", 3, cur);
    return 0;
}
View Code

 

posted @ 2019-10-13 00:40  Mrzdtz220  阅读(833)  评论(1)    收藏  举报