[LOJ523] [LibreOJ β Round # 3] Cardinal IOI (suspense) (Hall Theorem ring Tree _)

topic

LOJ523

Official explanations

analysis

For some reason, with the following "point the left" and "right of the dot" are replaced by the title of "sister" and "the boys."

According to the meaning of problems, apparently you can only come to a point to the left side or a right side two points even edge. This seems to enlighten us as to the left point is not the point, but as "relationship" between two points on the right side of (Correction: do not look at problem solution do not think). In other words, as the left edge point, right point as the point, we get a \ (n-\) points \ (m \) edges new FIG. If a left point to the \ (A \) and \ (B \) two points connected right side, joined in a new image connection \ ((a, b) \ ) edge (only the left connecting point a loopback point is the right side).

Consider the left point and the election must choose only one point to the right (note the title " ensure full match left side ") that the new maps every edge you must select one of its endpoints; and the new figure each point can only be select an edge. Intuitive put it, it is to give each edge directional, point to point what it means to choose this point. While the most of each point \ (1 \) .

The question then transformed into: Given an undirected graph, select each edge to give a direction to meet each point of penetration up to \ (1 \) . Two directions of each side has a respective weight, and the weight required to maximize.

Looks like or can not do?Solution to a problem through worship,Please note that this sentence again: ensure full match left side . The Hall Theorem (to prove the cushions), the left full match if and only if any of the selected size in a left \ (k (0 \ leq k \ leq m) \) subset, and the subset On the right side has edges that connect at least \ (K \) a. FIG placed on a new, randomly selected \ (K \) Size sides corresponding set of points is not less than \ (K \) .

What is this indicating? Consider for a connected component (i.e., maximum communication block) of the new image, the number of points it must be greater than the number of sides. And since communication is the number of points while adding up \ (1 \) . Thus a number of edges of the connected components is less than either points \ (1 \) , or is equal to the number of points. That is: either the tree or a tree ring.This figure even have such a beautiful nature.

Ring is bound tree tree outward directed ring. For ring tree edges, side of the tree if it is, then you must connect to a direction away from the ring. All edges must be connected into the ring in one direction (i.e., either all clockwise or all counterclockwise). Thus each ring tree only two options: either a clockwise rims plus all outgoing side of the tree, or all counterclockwise outward rims plus side of the tree. Maintenance can answer in both cases. When inward side of the tree if it is modified to ignore (Required not selected), directly to the outward side of the tree plus the difference between the final answer (mandatory), the direction corresponding to the updated rims answer.

Trees will be oriented to a point rooted directed tree, so to maintain with each point as the root of the answer, respectively. First just to find a spot for the dfs root sequence, then consider the contribution of each side: If an edge from the top down, then when the root is not at the endpoint within the sub-tree will contribute answers to; if an edge is from the bottom up, then when the next endpoint in the sub-tree root will contribute answer. The segment tree modify and maintain maximum range can be.

Code

As we all know, the question mouth ring tree easier (although this title is not easy), to write nausea. So patience to write and tune it.

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cctype>
#include <vector>
using namespace std;

namespace zyt
{
    template<typename T>
    inline bool read(T &x)
    {
        char c;
        bool f = false;
        x = 0;
        do
            c = getchar();
        while (c != EOF && c != '-' && !isdigit(c));
        if (c == EOF)
            return false;
        if (c == '-')
            f = true, c = getchar();
        do
            x = x * 10 + c - '0', c = getchar();
        while (isdigit(c));
        if (f)
            x = -x;
        return true;
    }
    template<typename T>
    inline void write(T x)
    {
        static char buf[20];
        char *pos = buf;
        if (x < 0)
            putchar('-'), x = -x;
        do
            *pos++ = x % 10 + '0';
        while (x /= 10);
        while (pos > buf)
            putchar(*--pos);
    }
    typedef pair<int, int> pii;
    const int N = 5e5 + 10;
    vector<pii> g[N];
    int m, n, T, a[N], b[N], dfn[N], fa[N], out[N], dfncnt, ecnt, v[N << 1], val[N][2], rot[N], opp[N << 1];
    bool iscir[N], incir[N], vis[N], dir[N << 1];
    pii e[N << 1];
    int f(const int x)
    {
        return x == fa[x] ? x : fa[x] = f(fa[x]);
    }
    void dfs(const int u, const int r)
    {
        vis[u] = true;
        dfn[u] = ++dfncnt;
        rot[u] = r;
        for (vector<pii>::iterator it = g[u].begin(); it != g[u].end(); it++)
        {
            int v = it->first;
            if (vis[v] || incir[v])
                continue;
            dfs(v, r);
        }
        out[u] = dfncnt;
    }
    int findcir(const int u, const int from)
    {
        static bool insta[N];
        if (insta[u])
            return u;
        insta[u] = true;
        for (vector<pii>::iterator it = g[u].begin(); it != g[u].end(); it++)
        {
            int v = it->first, tmp;
            if (opp[it->second] == from)
                continue;
            if (~(tmp = findcir(v, it->second)))
            {
                insta[u] = false;
                val[f(u)][0] += ::zyt::v[it->second];
                val[f(u)][1] += ::zyt::v[opp[it->second]];
                dir[it->second] = 0, dir[opp[it->second]] = 1;
                incir[u] = true;
                if (u != tmp)
                    return tmp;
                else
                    return -1;
            }
        }
        insta[u] = false;
        return -1;
    }
    namespace Segment_Tree
    {
        struct node
        {
            int mx, tag;
        }tree[N << 2];
        void add(const int rot, const int x)
        {
            tree[rot].mx += x, tree[rot].tag += x;
        }
        void pushdown(const int rot)
        {
            if (tree[rot].tag)
            {
                add(rot << 1, tree[rot].tag);
                add(rot << 1 | 1, tree[rot].tag);
                tree[rot].tag = 0;
            }
        }
        void update(const int rot)
        {
            tree[rot].mx = max(tree[rot << 1].mx, tree[rot << 1 | 1].mx);
        }
        void add(const int rot, const int lt, const int rt, const int ls, const int rs, const int x)
        {
            if (ls <= lt && rt <= rs)
                return void(add(rot, x));
            int mid = (lt + rt) >> 1;
            pushdown(rot);
            if (ls <= mid)
                add(rot << 1, lt, mid, ls, rs, x);
            if (rs > mid)
                add(rot << 1 | 1, mid + 1, rt, ls, rs, x);
            update(rot);
        }
        int query(const int rot, const int lt, const int rt, const int ls, const int rs)
        {
            if (ls <= lt && rt <= rs)
                return tree[rot].mx;
            int mid = (lt + rt) >> 1;
            pushdown(rot);
            if (rs <= mid)
                return query(rot << 1, lt, mid, ls, rs);
            else if (ls > mid)
                return query(rot << 1 | 1, mid + 1, rt, ls, rs);
            else
                return max(query(rot << 1, lt, mid, ls, rs), 
                            query(rot << 1 | 1, mid + 1, rt, ls, rs));
        }
    }
    int work()
    {
        using namespace Segment_Tree;
        read(m), read(n), read(T);
        for (int i = 0; i < n; i++)
            fa[i] = i;
        for (int i = 0; i < m; i++)
            read(a[i]);
        for (int i = 0; i < m; i++)
            read(b[i]);
        for (int i = 0; i < m; i++)
        {
            int x, y;
            x = (a[i] - b[i] + n) % n;
            y = (a[i] + b[i]) % n;
            if (x < y)
                swap(x, y);
            read(v[ecnt]);
            e[ecnt] = pii(x, y);
            //fprintf(stderr, "%d %d %d\n", x, y, v[ecnt]);
            g[x].push_back(pii(y, ecnt++));
            if (x != y)
            {
                read(v[ecnt]);
                e[ecnt] = pii(y, x);
                opp[ecnt - 1] = ecnt, opp[ecnt] = ecnt - 1;
                //fprintf(stderr, "%d %d %d\n", y, x, v[ecnt]);
                g[y].push_back(pii(x, ecnt++));
            }
            else
                opp[ecnt - 1] = ecnt - 1;
            if (f(x) == f(y))
                iscir[f(x)] = true;
            else
            {
                iscir[f(y)] |= iscir[f(x)];
                fa[f(x)] = f(y);
            }
        }
        for (int i = 0; i < n; i++)
            if (i == f(i) && iscir[i])
                findcir(i, -1);
        for (int i = 0; i < n; i++)
            if ((!iscir[f(i)] && i == f(i)) || incir[i])
                dfs(i, i);
        for (int i = 0; i < ecnt; i++)
        {
            if (iscir[f(e[i].first)])
            {
                if (!incir[e[i].first] || !incir[e[i].second])
                {
                    if (dfn[e[i].first] < dfn[e[i].second])
                        val[f(e[i].first)][0] += v[i], val[f(e[i].first)][1] += v[i];
                }
            }
            else
            {
                if (dfn[e[i].first] < dfn[e[i].second])
                {
                    int r = rot[e[i].first];
                    add(1, 1, n, dfn[r], dfn[e[i].second] - 1, v[i]);
                    if (out[e[i].second] < out[r])
                        add(1, 1, n, out[e[i].second] + 1, out[r], v[i]);
                }
                else
                    add(1, 1, n, dfn[e[i].first], out[e[i].first], v[i]);
            }
        }
        int q, ans = 0;
        for (int i = 0; i < n; i++)
            if (i == f(i))
            {
                if (iscir[i])
                    ans += max(val[i][0], val[i][1]);
                else
                    ans += query(1, 1, n, dfn[rot[i]], out[rot[i]]);
            }
        write(ans), putchar('\n');
        read(q);
        while (q--)
        {
            int x, vv;
            read(x), read(vv);
            x -= ans * T, vv -= ans * T;
            --x;
            if (iscir[f(e[x].first)])
            {
                int t = f(e[x].first);
                ans -= max(val[t][0], val[t][1]);
                if (!incir[e[x].first] || !incir[e[x].second])
                {
                    if (dfn[e[x].first] < dfn[e[x].second])
                        val[t][0] += vv - v[x], val[t][1] += vv - v[x];
                }
                else
                {
                    val[t][dir[x]] += vv - v[x];
                    if (e[x].first == e[x].second)
                        val[t][dir[x] ^ 1] += vv - v[x];
                }
                ans += max(val[t][0], val[t][1]);
            }
            else
            {
                int r = rot[e[x].first];
                ans -= query(1, 1, n, dfn[r], out[r]);
                if (dfn[e[x].first] < dfn[e[x].second])
                {
                    add(1, 1, n, dfn[r], dfn[e[x].second] - 1, vv - v[x]);
                    add(1, 1, n, out[e[x].second] + 1, out[r], vv - v[x]);
                }
                else
                    add(1, 1, n, dfn[e[x].first], out[e[x].first], vv - v[x]);
                ans += query(1, 1, n, dfn[r], out[r]);
            }
            v[x] = vv;
            write(ans), putchar('\n');
        }
        return 0;
    }
}
int main()
{
    return zyt::work();
}

Guess you like

Origin www.cnblogs.com/zyt1253679098/p/12010138.html