• 线段树合并训练记录


    [POI2011]ROT-Tree Rotations

    #include <cstdio>
    #include <algorithm>
    #include <queue>
    #include <stack>
    #include <string>
    #include <string.h>
    #include <map>
    #include <iostream>
    using namespace std;
    const int maxn = 4e6 + 50;
    const int mod = 20090717;
    typedef long long LL;
    int INF = 1e9;
    typedef pair<int, int> pii;
    #define fi first
    #define se second
    int n;
    struct node
    {
        int lc, rc;
        LL val;
    } tree[maxn];
    
    int tot = 1;
    int Build(){
        tot++;
        tree[tot].lc = tree[tot].rc = 0;
        tree[tot].val = 0;
        return tot;
    }
    
    int insert(int le, int ri, int pos){
        tree[++tot].val = 1;
        if(le == ri){
            return tot;
        }
        int mid = (le + ri) >> 1;
        int rt = tot;
        if(pos <= mid) tree[rt].lc = insert(le, mid, pos);
        else tree[rt].rc = insert(mid + 1, ri, pos);
        return rt;
    }
    
    LL ans, ans1, ans2;
    int merage(int le, int ri, int u, int v){
        if(!u || !v) return u | v;
        if(le == ri) {
            tree[u].val += tree[v].val;
            return u;
        }
        int mid = (le + ri) >> 1;
        ans1 += tree[tree[u].lc].val * tree[tree[v].rc].val;
        ans2 += tree[tree[u].rc].val * tree[tree[v].lc].val;
    
        tree[u].lc = merage(le, mid, tree[u].lc, tree[v].lc);
        tree[u].rc = merage(mid + 1, ri, tree[u].rc, tree[v].rc);
        tree[u].val = tree[tree[u].lc].val + tree[tree[u].rc].val; 
        return u; 
    }
    
    int dfs(){
        int u;
        scanf("%d", &u);
        if(u) return insert(1, n, u);
        int rt = merage(1, n, dfs(), dfs());
        // printf("ans1 = %I64d ans2 = %I64d
    ", ans1, ans2);
        ans += min(ans1, ans2);
        ans1 = ans2 = 0;
        return rt;
    }
    int main(int argc, char const *argv[])
    {
        scanf("%d", &n);
        dfs();
        printf("%lld
    ", ans);
        return 0;
    }
    

    洛谷:P4556 [Vani有约会]雨天的尾巴
    题解:树上差分 + 线段树合并

    #include <cstdio>
    #include <algorithm>
    #include <queue>
    #include <stack>
    #include <string>
    #include <string.h>
    #include <map>
    #include <iostream>
    #include <math.h>
    using namespace std;
    const int maxn = 6e6 + 50;
    const int mod = 20090717;
    typedef long long LL;
    int INF = 1e9;
    typedef pair<int, int> pii;
    #define fi first
    #define se second
    int n, m;
    int nn = 1e5 + 50;
    struct node
    {
        int lc, rc;
        int val;
    } tree[maxn];
    
    vector<int> vec[maxn], vec2[maxn];
    int tot;
    int Build(){
        tot++;
        tree[tot].lc = tree[tot].rc = 0;
        tree[tot].val = 0;
        return tot;
    }
    
    int root[maxn];
    int insert(int le, int ri, int pos, int val, int rt){
        if(le == ri){
            tree[rt].val += val;
            return rt;
        }
        int mid = (le + ri) >> 1;
    
        if(pos <= mid) {
            if(tree[rt].lc == 0) tree[rt].lc = Build();
            tree[rt].lc = insert(le, mid, pos, val, tree[rt].lc);
        }
        else {
            if(tree[rt].rc == 0) tree[rt].rc = Build();
            tree[rt].rc = insert(mid + 1, ri, pos, val, tree[rt].rc);
        }
        tree[rt].val = max(tree[tree[rt].lc].val, tree[tree[rt].rc].val);
        return rt;
    }
    
    int merage(int le, int ri, int u, int v){
        if(!u || !v) return u | v;
        if(le == ri) {
            tree[u].val += tree[v].val;
            return u;
        }
        int mid = (le + ri) >> 1;
        tree[u].lc = merage(le, mid, tree[u].lc, tree[v].lc);
        tree[u].rc = merage(mid + 1, ri, tree[u].rc, tree[v].rc);
        tree[u].val = max(tree[tree[u].lc].val, tree[tree[u].rc].val);
        return u; 
    }
    
    int Query(int le, int ri, int rt){
        if(!rt) return 0;
        if(le == ri){
            return le;
        }
        if(tree[rt].val == 0) return 0;
        int mid = (le + ri) >> 1;
        if(tree[tree[rt].lc].val >= tree[tree[rt].rc].val){
            return Query(le, mid, tree[rt].lc);
        } else {
            return Query(mid + 1, ri, tree[rt].rc);
        }
    }
    
    struct Edge
    {
        int to, next;
    } edge[maxn];
    
    int head[maxn], k;
    void add(int a, int b){
        edge[k].to = b;
        edge[k].next = head[a];
        head[a] = k++;
    }
    
    int ans[maxn];
    void dfs(int u, int pre){
        root[u] = Build();
        for(int i = head[u]; i != -1; i = edge[i].next){
            int to = edge[i].to;
            if(to == pre) continue;
            dfs(to, u);
            merage(1, nn, root[u], root[to]);
        }
        if(vec[u].size()){
            int len = vec[u].size();
            for(int i = 0; i < len; i++){
                int val = 1;
                if(vec[u][i] < 0) val = -1;
                insert(1, nn, abs(vec[u][i]), val, root[u]);
            }
        }
        ans[u] = Query(1, nn, root[u]);
    }
    
    int fa[maxn][30], depth[maxn];
    void dfs2(int u, int pre, int d){
        fa[u][0] = pre, depth[u] = d;
        for(int i = head[u]; i != -1; i = edge[i].next){
            int to = edge[i].to;
            if(to == pre) continue;
            dfs2(to, u, d + 1);
        }
    }
    
    void init(int root){
        dfs2(root, 0, 0);
        for(int j = 0; (1 << (j + 1)) < n; j++){
            for(int i = 1; i <= n; i++){
                if(fa[i][j] == 0) fa[i][j + 1] = 0;
                else fa[i][j + 1] = fa[fa[i][j]][j];
            }
        }
    }
    
    int LCA(int u, int v){
        if(depth[u] > depth[v]) swap(u, v);
        int temp = depth[v] - depth[u];
        for(int i = 0; (1 << i) <= temp; i++){
            if((1 << i) & temp) v = fa[v][i];
        }
        if(v == u) return u;
        for(int i = log2(n); i >= 0; i--){
            if(fa[u][i] != fa[v][i]){
                u = fa[u][i], v = fa[v][i];
            }
        }
        return fa[u][0];
    }
    int main(int argc, char const *argv[])
    {
        scanf("%d%d", &n, &m);
        for(int i = 1; i <= n; i++) head[i] = -1;
        for(int i = 1; i < n; i++){
            int x, y;
            scanf("%d%d", &x, &y);
            add(x, y);
            add(y, x);
        }
        init(1);
        for(int i = 1; i <= m; i++){
            int x, y, z;
            scanf("%d%d%d", &x, &y, &z);
            vec[x].push_back(z);
            vec[y].push_back(z);
            int lcaxy = LCA(x, y);
            vec[lcaxy].push_back(-z);
            vec[fa[lcaxy][0]].push_back(-z);
        }
        dfs(1, 0);
        for(int i = 1; i <= n; i++){
            printf("%d
    ", ans[i]);
        }
        return 0;
    }
    

    BZOJ 3545. [ONTAK2010]Peaks
    题解:并查集 + 线段树合并,每次用线段树维护一个联通块
    注:由于存在相同高度,所以要合并的两颗线段树可能存在相同的叶子节点,所以要对叶子节点特殊处理,否则会 (wa) 到爆炸

    #include <cstdio>
    #include <algorithm>
    #include <queue>
    #include <stack>
    #include <string>
    #include <string.h>
    #include <map>
    #include <iostream>
    #include <math.h>
    using namespace std;
    const int maxn = 1e5 + 50;
    const int MA = 1e7 + 50;
    const int mod = 20090717;
    typedef long long LL;
    int INF = 1e9;
    typedef pair<int, int> pii;
    #define fi first
    #define se second
    int n, m;
    struct node
    {
        int lc, rc;
        int val;
    } tree[MA];
    
    int a[maxn], lsh[maxn], id[maxn];
    int tot;
    int root[maxn];
    
    int fa[maxn];
    int Find(int x){
        if(x == fa[x]) return x;
        return fa[x] = Find(fa[x]);
    }
    struct Edge
    {
        int u, v, w;
        int id;
        bool operator < (const Edge &r) const{
            return w < r.w;
        }
    } edge[5 * maxn], quer[5 * maxn];
    
    
    void insert(int le, int ri, int pos, int &rt){
        if(!rt) rt = ++tot;
        tree[rt].val = 1;
        if(le == ri) return ;
        int mid = (le + ri) >> 1;
        if(pos <= mid) insert(le, mid, pos, tree[rt].lc);
        else insert(mid + 1, ri, pos, tree[rt].rc);
    }
    
    int imerage(int le, int ri, int u, int v){
        if(!u || !v) return u | v;
        if(le == ri) { // 这句一定要加上,否则相同的叶子节点不会合并,因为数据存在相同的高度
            tree[u].val += tree[v].val;
            return u;
        }
        // if(!tree[u].lc && !tree[u].rc){
        //     tree[u].val += tree[v].val;
        //     return u;
        // }
        int mid = (le + ri) >> 1;
        tree[u].lc = imerage(le, mid, tree[u].lc, tree[v].lc);
        tree[u].rc = imerage(mid + 1, ri, tree[u].rc, tree[v].rc);
        tree[u].val = tree[tree[u].lc].val + tree[tree[u].rc].val;
        return u;
    }
    
    int Query(int le, int ri, int rt, int sum){
        if(tree[rt].val < sum) return 0;
        if(le == ri) return le;
        int mid = (le + ri) >> 1;
        if(tree[tree[rt].rc].val >= sum) {
            return Query(mid + 1, ri, tree[rt].rc, sum);
        } else {
            return Query(le, mid, tree[rt].lc, sum - tree[tree[rt].rc].val);
        }
    }
    int ans[5 * maxn];
    int main(int argc, char const *argv[])
    {
        int q;
        scanf("%d%d%d", &n, &m, &q);
        for(int i = 1; i <= n; i++){
            fa[i] = i;
            scanf("%d", &a[i]);
            lsh[i] = a[i];
        }
    
        sort(lsh + 1, lsh + n + 1);
        int cnt;
        for(int i = 1; i <= n; i++){
            a[i] = lower_bound(lsh + 1, lsh + n + 1, a[i]) - lsh;
        }
    
        for(int i = 1; i <= m; i++){
            int u, v, w;
            scanf("%d%d%d", &u, &v, &w);
            edge[i] = {u, v, w, 0};
        }
        for(int i = 1; i <= q; i++){
            int u, x, k;
            scanf("%d%d%d", &u, &x, &k);
            quer[i] = {u, k, x, i};
        }
    
        sort(edge + 1, edge + m + 1);
        sort(quer + 1, quer + q + 1);
        cnt = 1;
    
        for(int i = 1; i <= n; i++) insert(1, n, a[i], root[i]);
        lsh[0] = -1;
        for(int i = 1; i <= q; i++){
            while(edge[cnt].w <= quer[i].w && cnt <= m){
                int u = edge[cnt].u, v = edge[cnt].v;
                u = Find(u), v = Find(v); // 这里写成fa[u], fa[v] 会MLE
                if(u == v){
                    cnt++;
                    continue;
                }
                imerage(1, n, root[u], root[v]);
                fa[v] = u;
                cnt++;
            }
            int u = quer[i].u;
            u = Find(u);
            int res = Query(1, n, root[u], quer[i].v);
            ans[quer[i].id] = lsh[res];
        }
        for(int i = 1; i <= q; i++){
            printf("%d
    ", ans[i]);
        }
        return 0;
    }
    
  • 相关阅读:
    如何利用azMan (Authorization Manager) 实现 rolebased的安全验证机制
    如何处理源dump文件的mscordacwks.dll文件与调试机上的版本不一致问题而无法使用extension cmd的问题
    UI thread client callback和UI thread WCF Service一起工作时死锁的形成原因及解决方法
    如何在 IIS 6.0 上配置托管的 Web 应用程序时使用 SPN(包括Network service ,domain acount, NLB, host header等各种情况)
    WCF中各种Transaction的分类及其相关参数的设置
    利用windbg调试class type,value type以及MethodTable等强化C#的基本概念
    如何自定义Attribute class并将其应用到相应的class
    谷歌浏览器F12调试页面学习
    上班族致富之道
    折半插入排序
  • 原文地址:https://www.cnblogs.com/PCCCCC/p/13371933.html
Copyright © 2020-2023  润新知