• CF603EPastoral Oddities


    /*
    LCT管子题(说的就是你 水管局长)
    
    首先能得到一个结论, 那就是当且仅当所有联通块都是偶数时存在构造方案
    
    LCT动态加边, 维护最小生成联通块, 用set维护可以删除的边, 假如现在删除后不影响全都是偶数大小的性质 就删除
    
    
    不清楚link为啥要makeroot两次 
    
    */
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<iostream>
    #include<queue>
    #include<set>
    #include<cmath>
    #define ll long long
    #define M 400010
    #define mmp make_pair
    using namespace std;
    int read() {
        int nm = 0, f = 1;
        char c = getchar();
        for(; !isdigit(c); c = getchar()) if(c == '-') f = -1;
        for(; isdigit(c); c = getchar()) nm = nm * 10 + c - '0';
        return nm * f;
    }
    int n, m, cnt, ln[M], rn[M];
    
    struct LCT {
        int fa[M], ch[M][2], sz[M], rev[M], val[M], mx[M], pl[M], zz[M];
    #define ls ch[x][0]
    #define rs ch[x][1]
        void pushup(int x) {
            sz[x] = sz[ls] + sz[rs] + zz[x] + 1;
            mx[x] = max(mx[ls], mx[rs]);
            pl[x] = (mx[x] == mx[ls]) ? pl[ls]: pl[rs];
            if(val[x] > mx[x]) mx[x] = val[x], pl[x] = x;
        }
    
        bool isr(int x) {
            return ch[fa[x]][0] != x && ch[fa[x]][1] != x;
        }
    
        void add(int x) {
            rev[x] ^= 1;
            swap(ls, rs);
        }
    
        void pushdown(int x) {
            if(rev[x]) {
                add(ls), add(rs);
                rev[x] = 0;
            }
        }
    
        void pd(int x) {
            if(!isr(x)) pd(fa[x]);
            pushdown(x);
        }
    
        void rotate(int x) {
            int y = fa[x], q = fa[y];
            bool dy = (ch[y][1] == x), dz = (ch[q][1] == y);
            if(!isr(y)) ch[q][dz] = x;
            fa[x] = q;
            fa[ch[x][dy ^ 1]] = y;
            ch[y][dy] = ch[x][dy ^ 1];
            ch[x][dy ^ 1] = y;
            fa[y] = x;
            pushup(y);
            pushup(x);
        }
    
        void splay(int x) {
            pd(x);
            while(!isr(x)) {
                int y = fa[x];
                if(!isr(y)) {
                    int q = fa[y];
                    if((ch[y][1] == x) ^ (ch[q][1] == y)) rotate(x);
                    else rotate(y);
                }
                rotate(x);
            }
        }
    
        void access(int x) {
            for(int y = 0; x; y = x, x = fa[x]) splay(x), zz[x] += sz[rs] - sz[y], rs = y, pushup(x);
        }
    
        void maker(int x) {
            access(x);
            splay(x);
            add(x);
        }
    
        int findr(int x) {
            access(x);
            splay(x);
            while(ls) pushdown(x), x = ls;
            return x;
        }
    
        void link(int x, int y) {
            maker(x);
            maker(y);
            fa[x] = y;
            zz[y] += sz[x];
            sz[y] += sz[x];
        }
    
        void split(int x, int y) {
            maker(x), access(y), splay(y);
        }
    
        void cut(int x, int y) {
            split(x, y);
            if(fa[x] != y && ch[x][1]) return;
            fa[x] = ch[y][0] = 0;
            pushup(y);
        }
    
        int query(int x, int y) {
            split(x, y);
            return pl[y];
        }
    
        int sum(int x) {
            maker(x);
            return ((sz[x] + 1) >> 1) & 1;
        }
    
    
    } lct;
    set<pair<int, int> >st;
    set<pair<int, int> >::reverse_iterator it;
    int main() {
        n = read(), m = read();
        cnt = n;
    //	for(int i = 1; i <= n; i++) lct.sz[i] = 1;
        for(int i = 1; i <= m; i++) {
            int vi = read(), vj = read();
            ln[i + n] = vi, rn[i + n] = vj;
            int x = read();
            lct.val[i + n] = x;
            lct.pushup(i + n);
            if(lct.findr(vi) != lct.findr(vj)) {
                if(lct.sum(vi)) cnt--;
                if(lct.sum(vj)) cnt--;
                lct.link(vi, i + n);
                lct.link(i + n, vj);
                lct.split(vi, vj);
                if(lct.sum(vj)) cnt++;
            } else {
                int pl = lct.query(vi, vj);
                if(lct.val[pl] <= x) {
                    if(cnt == 0) printf("%d
    ", st.rbegin()->first);
                    else puts("-1");
                    continue;
                }
                lct.cut(ln[pl], pl);
                lct.cut(rn[pl], pl);
                lct.link(vi, i + n);
                lct.link(i + n, vj);
                //	lct.split(vi, vj);
                st.erase(st.find(mmp(lct.val[pl], pl)));
            }
            st.insert(mmp(x, i + n));
            if(cnt) {
                puts("-1");
                continue;
            }
            while(1) {
                it = st.rbegin();
                int id = it->second;
                lct.cut(ln[id], id);
                lct.cut(id, rn[id]);
                if(lct.sum(ln[id]) || lct.sum(rn[id])) {
                    lct.link(ln[id], id);
                    lct.link(id, rn[id]);
                    break;
                }
                st.erase(*it);
            }
            printf("%d
    ", st.rbegin()->first);
        }
        return 0;
    }
    
    
    
    
  • 相关阅读:
    动态规划解决数字三角形问题
    动态规划,贪心,分治
    7-3 两个有序序列的中位数 (20分) log n的解法
    二分查找 单峰数组中的最大值 O(log n)
    数据库连接池 C3P0和 Druid
    SQL注入问题
    MATLAB spectrogram命令
    JDBC工具类
    Egret--拼接Rect实现用于新手引导的扣洞
    egrte-取消居中约束
  • 原文地址:https://www.cnblogs.com/luoyibujue/p/10524803.html
Copyright © 2020-2023  润新知