Codeforces Round #453 (Div. 1)

Posted ftae

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces Round #453 (Div. 1)相关的知识,希望对你有一定的参考价值。

C. Bipartite Segments

分析

在题目所给出的无向图中只能存在奇数长度的环,说明任意两个环一定无公共边,否则就会出现偶数长度的环。Tarjan 算法找环。
然后预处理 \(d[i]\) 表示从 \(i\) 开始向右最远延伸到的位置,即 \([i, d[i] + 1]\)这个区间就是不合法的,预处理后缀最小值即可。可以发现 \(d\) 呈单调不递减,对于每次询问 \((l,r)\) 可以二分找到 \(d[i]\geq r\)的最小下标,考虑左右两边算下贡献即可。

code

#include <bits/stdc++.h>
using namespace std;
const int N = 6e5 + 10;
int n, m, q;
struct Edge {
    int to, next;
} e[N];
int cnt, head[N];
void addedge(int u, int v) {
    e[cnt].to = v;
    e[cnt].next = head[u];
    head[u] = cnt++;
}
int sz, dfn[N], low[N], vis[N], rht[N];
long long sum[N];
stack<int> sta;
void tarjan(int u, int fa) {
    dfn[u] = low[u] = ++sz;
    vis[u] = 1;
    sta.push(u);
    for (int i = head[u]; ~i; i = e[i].next) {
        int v = e[i].to;
        if (v != fa) {
            if (!dfn[v]) {
                tarjan(v, u);
                low[u] = min(low[u], low[v]);
            } else if (vis[v] && low[u] > dfn[v]) {
                low[u] = dfn[v];
            }
        }
    }
    if (low[u] == dfn[u]) {
        int mn = 9999999, mx = 0;
        while (1) {
            int id = sta.top();
            sta.pop();
            mn = min(mn, id);
            mx = max(mx, id);
            vis[id] = 0;
            if (id == u) break;
        }
        if (mn != mx) rht[mn] = mx - 1;
    }
}
int main() {
    cin >> n >> m;
    cnt = sz = 0;
    memset(head, -1, sizeof head);
    for (int i = 0; i < m; i++) {
        int u, v;
        scanf("%d%d", &u, &v);
        addedge(u, v);
        addedge(v, u);
    }
    for (int i = 1; i <= n + 1; i++) {
        rht[i] = n;
    }
    for (int i = 1; i <= n; i++) {
        if (!dfn[i]) tarjan(i, -1);
    }
    for (int i = n; i >= 1; i--) {
        rht[i] = min(rht[i], rht[i + 1]);
        sum[i] = sum[i + 1] + rht[i] - i + 1;
    }
    cin >> q;
    while (q--) {
        int l, r;
        scanf("%d%d", &l, &r);
        int x = lower_bound(rht + l, rht + r + 1, r) - rht;
        cout << 1LL * (r - x + 1) * (r - x + 2) / 2 + sum[l] - sum[x] << endl;
    }
    return 0;
}

D. Weighting a Tree

分析

二分图脑洞好题!

首先要想到根据二分图分类,然后是构造一棵树(将点权转化为边权)。

首先如果题目给出的无向图就是一个二分图,那么要想答案存在,二分图左右两边结点的点权之和一定相等,因为此时对于二分图中的每一条边,都对两边的结点同时有贡献。那么对于这个二分图的任意生成树,我们都可以得到一个解。(不在树上的边权值都可以置为 0)
那如果不是二分图呢?
也就是说存在构成一条边的两个结点在“二分图”的同一边,如果此时“二分图”两边点权之和不等,那么我们可以改变构成这条边的结点的权值去平衡两边的点权和,然后和上面一样构造出一棵树即可。可以发现,这种情况下答案一定存在。
如果是二分图,且两边点权之和不等,那么答案就不存在了,因为我们找不到一条边去平衡两边的点权之和(因为此时任意边权都对两边的点权有贡献)。

code

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
vector<pair<int, int> > G[N];
int dep[N], vis[N], U, V, I;
long long c[N], ans[N];
void dfs1(int fa, int u) {
    for (auto to : G[u]) {
        int v = to.second;
        if (v != fa) {
            if (!dep[v]) {
                dep[v] = dep[u] + 1;
                dfs1(u, v);
            } else if (!((dep[u] - dep[v]) & 1)) {
                U = u;
                V = v;
                I = to.first;
            }
        }
    }
}
void dfs2(int u) {
    vis[u] = 1;
    for (auto to : G[u]) {
        int v = to.second;
        if (!vis[v]) {
            dfs2(v);
            ans[to.first] = c[v];
            c[u] -= c[v];
        }
    }
}
int main() {
    int n, m;
    cin >> n >> m;
    for (int i = 1; i <= n; i++) {
        cin >> c[i];
    }
    for (int i = 1; i <= m; i++) {
        int u, v;
        cin >> u >> v;
        G[u].push_back(pair<int, int>(i, v));
        G[v].push_back(pair<int, int>(i, u));
    }
    dep[1] = 1;
    dfs1(-1, 1);
    long long suml = 0, sumr = 0;
    for (int i = 1; i <= n; i++) {
        ((dep[i] & 1) ? suml : sumr) += c[i];
    }
    if (suml != sumr && !I) {
        cout << "NO\n";
        return 0;
    }
    long long x = suml - sumr >> 1;
    ans[I] = (dep[U] & 1) ? x : -x;
    c[U] -= ans[I];
    c[V] -= ans[I];
    dfs2(1);
    cout << "YES\n";
    for (int i = 1; i <= m; i++) {
        cout << ans[i] << " \n"[i == m];
    }
    return 0;
}

以上是关于Codeforces Round #453 (Div. 1)的主要内容,如果未能解决你的问题,请参考以下文章

Codeforces Round #453 (Div. 2) a-c

做题Codeforces Round #453 (Div. 1) D. Weighting a Tree——拆环

Codeforces Round #436 E. Fire(背包dp+输出路径)

[ACM]Codeforces Round #534 (Div. 2)

CodeForces 453A 概率题

CodeForces 453A