HDU 6218 (线段树+set)

HDU 6218 Bridge

Problem :
给一个2×n的矩阵,一开始矩阵所有相邻点之间有一条边。有其、个询问,每次给出两个相邻的点的坐标,将其中的边删除或者添加,问如此操作之后整张图的割边数量。
, q<=2*10^5, 图始终保证联通。
Solution :
首先可以发现不能成为割边的边,一定被某个环所包含。因此只要维护每个环的大小即可。
若某条横边在两行中均出现了两次,才有可能构成环。用set来维护所有连续的横边。再用线段树来维护所有竖边的位置。
计算一条连续的横边产生的不能成为割边的数量,统计其中最左和最右的竖边以及竖边的数量就行了。

#include 

using namespace std;

const int N = 2e5 + 8;
const int INF = 1e9 + 7;

#define endl "\n"
#define y1 qqq
struct node
{
    int l, r;
    node(){}
    node(int l, int r):l(l),r(r){}
    bool operator < (const node &b) const
    {
        return l < b.l;
    }
};
multiset  S;
int n, q, mtot, num;
int cnt[N];
class Segment_Tree
{
public:
    int tagmin[N << 2], tagmax[N << 2], tagsum[N << 2];
    void pushup(int rt)
    {
        tagmin[rt] = min(tagmin[rt << 1], tagmin[rt << 1 | 1]);
        tagmax[rt] = max(tagmax[rt << 1], tagmax[rt << 1 | 1]);
        tagsum[rt] = tagsum[rt << 1] + tagsum[rt << 1 | 1];
    }
    void build(int l, int r, int rt)
    {
        tagmin[rt] = INF; tagmax[rt] = 0; tagsum[rt] = 0;
        if (l == r)
        {
            tagmin[rt] = tagmax[rt] = l;
            tagsum[rt] = 1;
            return;
        }
        int m = l + r >> 1;
        build(l, m, rt << 1);
        build(m + 1, r, rt << 1 | 1);
        pushup(rt);
    }
    void update(int x, int op, int l, int r, int rt)
    {
        if (l == r)
        {
            if (op == 1)
            {
                tagmin[rt] = tagmax[rt] = l; tagsum[rt] = 1;
            }
            else
            {
                tagmin[rt] = INF; tagmax[rt] = 0; tagsum[rt] = 0;
            }
            return;
        }
        int m = l + r >> 1;
        if (x <= m) update(x, op, l, m, rt << 1);
        else update(x, op, m + 1, r, rt << 1 | 1);
        pushup(rt);
    }
    void querymax(int L, int R, int l, int r, int rt, int &ans)
    {
        if (L <= l && r <= R)
        {
            ans = max(ans, tagmax[rt]);
            return;
        }
        int m = l + r >> 1;
        if (L <= m) querymax(L, R, l, m, rt << 1, ans);
        if (m <  R) querymax(L, R, m + 1, r, rt << 1 | 1, ans);
    }
    void querymin(int L, int R, int l, int r, int rt, int &ans)
    {
        if (L <= l && r <= R)
        {
            ans = min(ans, tagmin[rt]);
            return;
        }
        int m = l + r >> 1;
        if (L <= m) querymin(L, R, l, m, rt << 1, ans);
        if (m <  R) querymin(L, R, m + 1, r, rt << 1 | 1, ans);
    }
    void querysum(int L, int R, int l, int r, int rt, int &ans)
    {
        if (L <= l && r <= R)
        {
            ans += tagsum[rt];
            return;
        }
        int m = l + r >> 1;
        if (L <= m) querysum(L, R, l, m, rt << 1, ans);
        if (m <  R) querysum(L, R, m + 1, r, rt << 1 | 1, ans);
    }
}T;
int calc(int l, int r)
{
    int L = INF, R = -INF, sum = 0;
    T.querymin(l, r, 1, n, 1, L);
    T.querymax(l, r, 1, n, 1, R);
    T.querysum(l, r, 1, n, 1, sum);
    if (sum <= 1) return 0;
    return (R - L) * 2 + sum;
}
void init()
{
    cin >> n >> q;
    T.build(1, n, 1);
    S.clear();
    for (int i = 1; i <= n; ++i) cnt[i] = 2;
    S.insert(node(1, n));
    S.insert(node(-1, -1));
    S.insert(node(n + 2, n + 2));
    mtot = 3 * n - 2;
    num = calc(1, n);
}
void work_row_add(int x)
{
    auto l = S.upper_bound(node(x, x + 1)); l--;
    auto r = S.lower_bound(node(x, x + 1));
    cnt[x]++; mtot++;
    if (cnt[x] == 1)
    {
        cout << mtot - num << endl;
        return;
    }
    if (l->r == x && r->l == x + 1)
    {
        num -= calc(l->l, l->r);
        num -= calc(r->l, r->r);
        num += calc(l->l, r->r);
        S.insert(node(l->l, r->r));
        S.erase(l);
        S.erase(r);
    }
    else if (l->r == x && r->l != x + 1)
    {
        num -= calc(l->l, l->r);
        num += calc(l->l, x + 1);
        S.insert(node(l->l, x + 1));
        S.erase(l);
    }
    else if (l->r != x && r->l == x + 1)
    {
        num -= calc(r->l, r->r);
        num += calc(x, r->r);
        S.insert(node(x, r->r));
        S.erase(r);
    }
    else if (l->r != x && r->l != x + 1)
    {
        num += calc(x, x + 1);
        S.insert(node(x, x + 1));
    }
}
void work_row_del(int x)
{
    auto p = S.upper_bound(node(x, x + 1)); p--;
    cnt[x]--; mtot--;
    if (cnt[x] == 0) return;
    if (p->l == x && p->r == x + 1)
    {
        num -= calc(x, x + 1);
        S.erase(p);
    }
    else if (p->l == x && p->r != x + 1)
    {
        num += calc(x+1,p->r);
        num -= calc(p->l,p->r);
        S.insert(node(x+1,p->r));
        S.erase(p);
    }
    else if (p->l != x && p->r == x + 1)
    {
        num += calc(p->l,x);
        num -= calc(p->l,p->r);
        S.insert(node(p->l,x));
        S.erase(p);
    }
    else if (p->l != x && p->r != x + 1)
    {
        num -= calc(p->l, p->r);
        num += calc(p->l, x);
        num += calc(x+1, p->r);
        S.insert(node(p->l, x));
        S.insert(node(x+1, p->r));
        S.erase(p);
    }
}
void work_col_add(int x)
{
    auto p = S.upper_bound(node(x, x)); p--;
    mtot++;
    if (p->r >= x)
    {
        num -= calc(p->l, p->r);
        T.update(x, 1, 1, n, 1);
        num += calc(p->l, p->r);
    }
    else
    {
        T.update(x, 1, 1, n, 1);
    }
}
void work_col_del(int x)
{
    auto p = S.upper_bound(node(x, x)); p--;
    mtot--;
    if (p->r >= x)
    {
        num -= calc(p->l, p->r);
        T.update(x, -1, 1, n, 1);
        num += calc(p->l, p->r);
    }
    else
    {
        T.update(x, -1, 1, n, 1);
    }
}
void solve()
{
    for (; q; --q)
    {
        int op, x1, y1, x2, y2;
        cin >> op >> x1 >> y1 >> x2 >> y2;

        if (y1 > y2) swap(y1, y2);
        if (op == 1)
            if (x1 == x2) work_row_add(y1);
            else work_col_add(y1);
        else
            if (x1 == x2) work_row_del(y1);
            else work_col_del(y1);
        cout << mtot - num << endl;
    }
}
int main()
{
    cin.sync_with_stdio(0);
    int T; cin >> T;
    for (int cas = 1; cas <= T; ++cas)
    {
        init();
        solve();
    }
}


转载于:https://www.cnblogs.com/rpSebastian/p/7834027.html

你可能感兴趣的:(HDU 6218 (线段树+set))