zoukankan      html  css  js  c++  java
  • Luogu 4556 雨天的尾巴

    主席树+线段树合并。

    首先我们想一想如果只有一个结点的话,我们弄一个权值线段树就可以随便维护了。

    那么我们可以运用差分的思想,把一个询问拆成四个操作,对于一个询问$(x, y, v)$,我们在$x$的$k$处$ + 1$,在$y$的$k$处$ + 1$,在$lca(x, y)$处$ - 1$,在$fa(lca(x, y))$处$ - 1$,那么每一个点最后的权值线段树的样子就相当于把它和它的子树中的权值线段树全部合并之后得到的线段树。

    动态开点就可以了。

    前置技能:线段树合并。     戳这里

    这样子我们往下搜一遍把每一个点和它的儿子合并,然后记录一下答案就可以了。

    不会算时间复杂度QωQ。

    另外,这题数据很卡,我写了内存回收 + $queue$开了$O2$才卡过。

    Code:

    #include <cstdio>
    #include <cstring>
    #include <queue>
    #include <algorithm>
    using namespace std;
    
    const int N = 1e5 + 5;
    const int Lg = 19;
    
    int n, m, maxn = 0, tot = 0, head[N], ans[N];
    int fa[N][Lg], dep[N], inx[N], iny[N], inv[N], val[N];
    
    struct Edge {
        int to, nxt;
    } e[N << 1];
    
    inline void add(int from, int to) {
        e[++tot].to = to;
        e[tot].nxt = head[from];
        head[from] = tot;
    }
    
    struct Innum {
        int val, id;
    } in[N];
    
    bool cmp(const Innum &x, const Innum &y) {
        if(x.val != y.val) return x.val < y.val;
        else return x.id < y.id;
    }
    
    inline void swap(int &x, int &y) {
        int t = x; x = y; y = t;
    }
    
    inline void chkMax(int &x, int y) {
        if(y > x) x = y;
    }
    
    inline int min(int x, int y) {
        return x > y ? y : x;
    }
    
    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;
    }
    
    inline void discrete() {
        sort(in + 1, in + 1 + m, cmp);
        for(int cnt = 0, i = 1; i <= m; i++) {
            if(in[i].val != in[i - 1].val) ++cnt;
            chkMax(maxn, cnt);
            inv[in[i].id] = cnt;
            val[cnt] = in[i].val;
        }
    }
    
    void dfs(int x, int fat, int depth) {
        dep[x] = depth, fa[x][0] = fat;
        for(int i = 1; i <= 18; i++)
            fa[x][i] = fa[fa[x][i - 1]][i - 1];
        for(int i = head[x]; i; i = e[i].nxt) {
            int y = e[i].to;
            if(y == fat) continue;
            dfs(y, x, depth + 1);
        }
    }
    
    inline int getLca(int x, int y) {
        if(dep[x] < dep[y]) swap(x, y);
        for(int i = 18; i >= 0; i--)
            if(dep[fa[x][i]] >= dep[y])
                x = fa[x][i];
        if(x == y) return x;
        for(int i = 18; i >= 0; i--)
            if(fa[x][i] != fa[y][i])
                x = fa[x][i], y = fa[y][i];
        return fa[x][0];
    }
    
    namespace PSegT {
        struct Node {
            int lc, rc, sum, col;
        } s[N * 60];
        
        int root[N], nodeCnt = 0;
            
        queue <int> Q;
        
        inline void push(int x) {
            Q.push(x);
        }
        
        inline int newNode() {
            if(Q.empty()) return ++nodeCnt;
            else {
                int res = Q.front();
                Q.pop();
                return res;
            }
        }
        
        #define lc(p) s[p].lc
        #define rc(p) s[p].rc
        #define sum(p) s[p].sum
        #define col(p) s[p].col
        #define mid ((l + r) >> 1)
        
        inline void up(int p) {
            if(!p) return;
            if(sum(lc(p)) < sum(rc(p))) col(p) = col(rc(p)), sum(p) = sum(rc(p));
            else col(p) = col(lc(p)), sum(p) = sum(lc(p));
        }
        
        void modify(int &p, int l, int r, int x, int v) {
            if(!p) p = newNode();
            if(l == r) {
                sum(p) += v;
                if(sum(p) > 0) col(p) = l;
                else col(p) = 0;
                return;
            }
            
            if(x <= mid) modify(lc(p), l, mid, x, v);
            else modify(rc(p), mid + 1, r, x, v);
            up(p);
        }
        
        int merge(int u, int v, int l, int r) {
            if(!u || !v) return u + v;
            int p = newNode();
            if(l == r) {
                sum(p) = sum(u) + sum(v);
                if(sum(p) > 0) col(p) = l;
                else col(p) = 0;
            } else {
                lc(p) = merge(lc(u), lc(v), l, mid);
                rc(p) = merge(rc(u), rc(v), mid + 1, r);
                up(p);        
            }    
            push(u), push(v);
            return p;
        }
        
    } using namespace PSegT;
    
    void solve(int x) {
        for(int i = head[x]; i; i = e[i].nxt) {
            int y = e[i].to;
            if(y == fa[x][0]) continue;
            solve(y);
            root[x] = merge(root[x], root[y], 1, maxn);
        }
        
    /*    printf("%d: ", x);
        for(int i = 1; i <= maxn; i++)
            printf("%d ", query(root[id[x] - 1], root[id[x]], 1, maxn, i));
        printf("
    ");    */
        
        ans[x] = val[s[root[x]].col];
    }
    
    int main() {
        read(n), read(m);
        for(int x, y, i = 1; i < n; i++) {
            read(x), read(y);
            add(x, y), add(y, x);
        }
        dfs(1, 0, 1);
        
    //    maxn = 1e5;
    
        for(int i = 1; i <= m; i++) {
            read(inx[i]), read(iny[i]), read(inv[i]);
            in[i].id = i, in[i].val = inv[i];
        }
        discrete();
        
        for(int x, y, v, z, w, i = 1; i <= m; i++) {
            x = inx[i], y = iny[i], v = inv[i];
            z = getLca(x, y), w = fa[z][0];
            
    /*        vec[x].push_back(pin(v, 1));
            vec[y].push_back(pin(v, 1));
            vec[z].push_back(pin(v, -1));
            if(w) vec[w].push_back(pin(v, -1));    */
            
            modify(root[x], 1, maxn, v, 1);
            modify(root[y], 1, maxn, v, 1);
            modify(root[z], 1, maxn, v, -1);
            if(w) modify(root[w], 1, maxn, v, -1);
        }            
        
    /*    printf("
    ");
        for(int i = 1; i <= n; i++) {
            printf("%d: ", i);
            for(int j = 1; j <= maxn; j++)
                printf("%d ", query(root[id[i] - 1], root[id[i] + siz[i] - 1], 1, maxn, j));
            printf("
    ");
        }    
        printf("
    ");    */
        
        solve(1);
        
        for(int i = 1; i <= n; i++)
            printf("%d
    ", ans[i]);
        
        return 0;
    }
    View Code
  • 相关阅读:
    通过应用程序域AppDomain加载和卸载程序集(转自张逸)
    Asp.net 2.0 中获取控件输出的Html代码 (转)
    工作和学习
    查询数据库中的所有表
    观活动板房感怀
    温心之旅
    读书无用论是21世纪最大的阴谋
    我渴望女人,但我更渴望成功
    外面比家里亮
    近来,可好?
  • 原文地址:https://www.cnblogs.com/CzxingcHen/p/9671398.html
Copyright © 2011-2022 走看看