• bzoj 3551


    按照困难度升序排序
    Kruskal重构树
    这样一来一个点的子树中的所有困难值都小于改点的困难值
    对于每次询问
    倍增找出困难值最大且小于x的点
    该点的子树中的第k大就是询问的答案
    主席书维护区间k大

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    #include <cstring>
    
    using namespace std;
    const int N = 1e5 + 10, M = 2e5 + 10;
    
    int n, m, Q;
    int A[N << 1], high[N << 1], val[N << 1];
    struct Node {
        int u, v, hard;
    } Edge[M * 10];
    struct Node_ {
        int v, nxt;
    } G[M * 10];
    int fa[N << 1];
    int Root[N << 1];
    int W[M * 10];
    int head[N << 1];
    int Lson[M * 10], Rson[M * 10];
    int now;
    int tree[N << 1], bef[N << 1], lst[N << 1], rst[N << 1], Tree;
    int N_;
    int f[N << 1][30];
    int Ans;
    int Segjs;
    int impjs;
    
    #define gc getchar()
    inline int read() {
        int x = 0; char c = gc;
        while(c < '0' || c > '9') c = gc;
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = gc;
        return x;
    }
    
    inline bool Cmp(Node a, Node b) {
        return a.hard < b.hard;
    }
    
    int Get(int x) {
        return fa[x] == x ? x : fa[x] = Get(fa[x]);
    }
    
    inline void Add(int u, int v) {
        G[++ now].v = v;
        G[now].nxt = head[u];
        head[u] = now;
    }
    
    inline void Pre() {
        for(int i = 1; i <= 20; i ++) for(int j = 1; j <= n * 2 - 1; j ++) f[j][i] = f[f[j][i - 1]][i - 1];
    }
    
    inline void Fill(int x, int y) {
        Lson[x] = Lson[y], Rson[x] = Rson[y], W[x] = W[y];
    }
    
    inline int Imp_find(int u, int x) {
        for(int i = 20; i >= 0; i --) if(f[u][i] && val[f[u][i]] <= x) u = f[u][i];
        return u;
    }
    
    inline void Kruskal() {
        sort(Edge + 1, Edge + m + 1, Cmp);
        impjs = n;
        for(int i = 1; i <= n * 2; i ++) fa[i] = i;
        for(int i = 1; i <= n * 2; i ++) head[i] = -1;
        for(int i = 1; i <= m; i ++) {
            int fau = Get(Edge[i].u), fav = Get(Edge[i].v);
            if(fau != fav) {
                impjs ++;
                val[impjs] = Edge[i].hard;
                fa[fau] = fa[fav] = impjs;
                Add(impjs, fau), Add(fau, impjs), Add(impjs, fav), Add(fav, impjs);
            }
            if(impjs == n * 2 - 1) break;
        }
    }
    
    void Dfs(int u, int fa) {
        if(u <= n) {
            lst[u] = rst[u] = ++ Tree;
            bef[Tree] = u;    
        }
        else lst[u] = n;
        for(int i = head[u]; ~ i; i = G[i].nxt) {
            int v = G[i].v;
            if(v == fa) continue;
            f[v][0] = u;
            Dfs(v, u);
            rst[u] = max(rst[u], rst[v]), lst[u] = min(lst[u], lst[v]);
        }
    }
    
    void Insert(int &rt, int l, int r, int x) {
        Fill(++ Segjs, rt);
        rt = Segjs;
        W[rt] ++;
        if(l == r) return ;
        int mid = (l + r) >> 1;
        if(x <= mid) Insert(Lson[rt], l, mid, x);
        else Insert(Rson[rt], mid + 1, r, x);
    }
    
    void Sec_A(int jd1, int jd2, int l, int r, int k) {
        if(l == r) {Ans = l; return ;}
        if(W[jd2] - W[jd1] < k) {Ans = -1; return ;}
        int mid = (l + r) >> 1;
        if(W[Rson[jd2]] - W[Rson[jd1]] >= k) Sec_A(Rson[jd1], Rson[jd2], mid + 1, r, k);
        else Sec_A(Lson[jd1], Lson[jd2], l, mid, k - (W[Rson[jd2]] - W[Rson[jd1]]));
    }
    
    int main() {
        n = read(), m = read(), Q = read();
        for(int i = 1; i <= n; i ++) 
            A[i] = read(), high[i] = A[i];
        for(int i = 1; i <= m; i ++) {
            int a = read(), b = read(), c = read();
            Edge[i] = (Node) {a, b, c};
        }
        sort(A + 1, A + n + 1);
        int a = unique(A + 1, A + n + 1) - A - 1;
        for(int i = 1; i <= n; i ++) 
            high[i] = lower_bound(A + 1, A + a + 1, high[i]) - A;
        Kruskal();
        Dfs(impjs, 0);
        Pre();
        for(int i = 1; i <= n; i ++) {
            Root[i] = Root[i - 1];
            Insert(Root[i], 1, n, high[bef[i]]);
        }
        for(; Q; Q --) {
            int v = read(), x = read(), k = read();
            if(Ans != -1) v ^= Ans, x ^= Ans, k ^= Ans;
            int use = Imp_find(v, x);
            Sec_A(Root[lst[use] - 1], Root[rst[use]], 1, n, k);
            if(Ans != -1) Ans = A[Ans];
            printf("%d
    ", Ans);
        }
        return 0;
    }
  • 相关阅读:
    mysql的复制
    web页面请求历程
    django工作原理简介
    http协议
    路由器和交换机的区别
    OSI七层模型
    TCP/IP协议总结
    IO复用
    僵尸进程和孤儿进程
    java源代码如何打成jar包
  • 原文地址:https://www.cnblogs.com/shandongs1/p/9499681.html
Copyright © 2020-2023  润新知