• Luogu 3665 [USACO17OPEN]Switch Grass 切换牧草


    BZOJ 4777 被权限了。

    这道题的做法看上去不难,但是感觉自己yy不出来。

    首先是两个结论:

    1、答案一定是连接着两个异色点的一条边。

    2、答案一定在最小生成树上。

    感觉看到了之后都比较显然,自己想……算了吧……想不出来的……

    那么我们可以对每一个点开一个以颜色为下标的线段树,对这棵树存一存它儿子的颜色到它的距离,然后在叶子结点维护一个$multiset$,把所有颜色相同的点都丢进去,然后维护一个最小值$lst_x = min(query(1, 1, k, 1, col_x - 1), query(1, 1, n, col_x  + 1, k))$。

    再全局维护一个$multiset$,每一次更改颜色的时候加入删除就好了。

    时间复杂度$O(nlog^2n)$。

    在Luogu上需要氧气。

    Code:

    #include <cstdio>
    #include <cstring>
    #include <set>
    #include <algorithm>
    using namespace std;
    typedef long long ll;
    
    const int N = 2e5 + 5;
    const int inf = 1 << 30;
    
    int n, m, k, qn, col[N], ufs[N], tot = 0, head[N];
    int lst[N], idCnt = 0, id[N * 40], fa[N], eVal[N];
    multiset <int> ans, w[N * 40];
    
    struct Pathway {
        int u, v, val;
        
        friend bool operator < (const Pathway &x, const Pathway &y) {
            return x.val < y.val;
        }
        
    } pat[N];
    
    struct Edge {
        int to, nxt, val;
    } e[N << 1];
    
    inline void add(int from, int to, int val) {
        e[++tot].to = to;
        e[tot].val = val;
        e[tot].nxt = head[from];
        head[from] = tot;
    }
    
    inline void addEdge(int x, int y, int v) {
        add(x, y, v), add(y, x, v);
    }
    
    inline void read(int &X) {
        X = 0; char ch = 0; int op = 1;
        for(; ch > '9' || ch < '0'; ch = getchar())
            if(ch == '-') op = -1;
        for(; ch >= '0' && ch <= '9'; ch = getchar())
            X = (X << 3) + (X << 1) + ch - 48;
        X *= op;
    }
    
    int find(int x) {
        return x == ufs[x] ? x : ufs[x] = find(ufs[x]);
    }
    
    inline void kruskal() {
        sort(pat + 1, pat + 1 + m);
        int cnt = 0;
        for(int i = 1; i <= n; i++) ufs[i] = i;
        for(int i = 1; i <= m; i++) {
            int u = find(pat[i].u), v = find(pat[i].v);
            if(u == v) continue;
            ufs[u] = v;
            addEdge(pat[i].u, pat[i].v, pat[i].val);
            ++cnt;
            if(cnt >= n - 1) break;
        }
    }
    
    inline int min(int x, int y) {
        return x > y ? y : x;
    }
    
    inline void chkMin(int &x, int y) {
        if(y < x) x = y;
    }
    
    namespace SegT {
        struct Node {
            int lc, rc, mn;
        } s[N * 40];
        
        int root[N], nodeCnt = 0;
        
        #define lc(p) s[p].lc
        #define rc(p) s[p].rc
        #define mn(p) s[p].mn
        #define mid ((l + r) >> 1)
        
        inline void up(int p) {
            mn(p) = min(mn(lc(p)), mn(rc(p)));
        }
        
        void ins(int &p, int l, int r, int x, int v) {
            if(!p) mn(p = ++nodeCnt) = inf;
            if(l == r) {
                if(!id[p]) id[p] = ++idCnt;
                w[id[p]].insert(v);
                mn(p) = *(w[id[p]].begin());
                return;
            }
            
            if(x <= mid) ins(lc(p), l, mid, x, v);
            else ins(rc(p), mid + 1, r, x, v);
            up(p);
        }
        
        void del(int &p, int l, int r, int x, int v) {
            if(l == r) {
                w[id[p]].erase(w[id[p]].find(v));
                if(w[id[p]].empty()) mn(p) = inf;
                else mn(p) = *(w[id[p]].begin());
                return;
            }    
            
            if(x <= mid) del(lc(p), l, mid, x, v);
            else del(rc(p), mid + 1, r, x, v);
            up(p);
        }
        
        int query(int p, int l, int r, int x, int y) {
            if(!p) return inf;
            if(x <= l && y >= r) return mn(p);
            
            int res = inf;
            if(x <= mid) chkMin(res, query(lc(p), l, mid, x, y));
            if(y > mid) chkMin(res, query(rc(p), mid + 1, r, x, y));
            return res;
        }
        
    } using namespace SegT;
    
    inline int queryMin(int x) {
        int res = inf;
        if(col[x] != 1) chkMin(res, query(root[x], 1, k, 1, col[x] - 1));
        if(col[x] != k) chkMin(res, query(root[x], 1, k, col[x] + 1, k));
        return res;
    }
    
    void dfs(int x, int fat) {
        fa[x] = fat;
        for(int i = head[x]; i; i = e[i].nxt) {
            int y = e[i].to;
            if(y == fat) continue;
            eVal[y] = e[i].val;
            ins(root[x], 1, k, col[y], e[i].val);
            dfs(y, x);
        }
        if(root[x]) {
            lst[x] = queryMin(x);
            ans.insert(lst[x]);
        }
    }
    
    int main() {
    //    freopen("2.in", "r", stdin);
    //    freopen("my.out", "w", stdout);
        
        read(n), read(m), read(k), read(qn);
        for(int i = 1; i <= m; i++) 
            read(pat[i].u), read(pat[i].v), read(pat[i].val);
        kruskal();
        
        for(int i = 1; i <= n; i++) read(col[i]);
        
        mn(0) = inf;
        dfs(1, 0);
        
        for(int x, v; qn--; ) {
            read(x), read(v);
            int pre = col[x];
            col[x] = v;
            if(root[x]) {
                ans.erase(ans.find(lst[x]));
                lst[x] = queryMin(x);
                ans.insert(lst[x]);
            }
            if(fa[x]) {
                ans.erase(ans.find(lst[fa[x]]));
                del(root[fa[x]], 1, k, pre, eVal[x]);
                ins(root[fa[x]], 1, k, v, eVal[x]);
                lst[fa[x]] = queryMin(fa[x]);
                ans.insert(lst[fa[x]]);
            }
            
            printf("%d
    ", *(ans.begin()));
        }
        return 0;
    }
    View Code
  • 相关阅读:
    C#中 @ 的用法
    ASP.NET页面间传值
    ASP.NET中常用的文件上传下载方法
    把图片转换为字符
    把图片转换为字符
    JavaScript 时间延迟
    Using WSDLs in UCM 11g like you did in 10g
    The Definitive Guide to Stellent Content Server Development
    解决RedHat AS5 RPM安装包依赖问题
    在64位Windows 7上安装Oracle UCM 10gR3
  • 原文地址:https://www.cnblogs.com/CzxingcHen/p/9870907.html
Copyright © 2020-2023  润新知