• 主席树,开坑POJ2104,EOJ3335&hdu6162,hdu5919


    一些废话

    去年自己一知半解写的blog

    blog1

    blog2

    blog3

    还没看的blog

    n个树,其实是有n个线段树

    每个线段树记录前n个数插入的状态,是把整个序列排序之后插入自己该在的位置(类似于树状数组求逆序对的那种插入姿势)

    每次新建一个线段树大部分节点都是从前一棵树上掰下来的,公用的,所以每次增加nlogn个节点

    poj2104

    拿去年的板子改的,去年的代码好丑,换成舒服的风格

    # include <cstdio>
    # include <cstring>
    # include <iostream>
    # include <algorithm>
    using namespace std;
    const int N = 1e5 + 7;
    int arr[N];  //arr[]  原数组的数在rank[]中的位置;
    int Rank[N]; //rank[] 原数组离散化
    
    struct ChairTree{
        #define sum(x) tree[x].w
        #define lson tree[rt].lc, tree[rt1].lc, l, m
        #define rson tree[rt].rc, tree[rt1].rc, m+1, r
        struct node{
            int lc, rc, w;
            node(){}
        } tree[N * 20];
        int root[N], cnt;
        void build(){
            root[0] = cnt = 0;
            memset(tree, 0, sizeof(tree));
        }
    
        void add(int pos, int val, int &rt, int rt1, int l, int r){
            tree[rt = ++cnt] = tree[rt1];
            tree[rt].w += val;
            if (l == r) return;
            int m = (l + r) >> 1;
            if (pos <= m) add(pos, val, lson);
            else add(pos, val, rson);
        }
    
        int query(int k, int rt, int rt1, int l, int r){
            if (l == r) return l;
            int lsize = sum(tree[rt1].lc) - sum(tree[rt].lc);
            int m = (l + r) >> 1;
            if (lsize >= k) return query(k, lson);
            else return query(k - lsize, rson);
        }
    } T;
    
    int main(){
        //freopen("in.txt","r",stdin);
        int _, l, r, k, n, q;
        for (; ~scanf("%d%d", &n, &q);){
            T.build();
            for (int i = 1; i <= n; i++) {
                scanf("%d", &arr[i]);
                Rank[i] = arr[i];
            }
            sort(Rank + 1, Rank + n+1);//Rank存储原值
            int m = unique(Rank + 1, Rank + n +1) - (Rank + 1);
            for (int i = 1; i <= n; i++) {//离散化后的数组,仅仅用来更新
                arr[i] = lower_bound(Rank + 1, Rank + n+1, arr[i]) - Rank;
            }
            for (int i = 1; i <= n; i++){
                T.add(arr[i], 1, T.root[i], T.root[i-1], 1, n);
            }
            for (; q--;){
                scanf("%d%d%d", &l, &r, &k);
                int pos = T.query(k, T.root[l-1], T.root[r], 1, n);
                printf("%d
    ", Rank[pos]);
            }
        }
        return 0;
    }
    
    

    EOJ3335&&hdu6162

    多校第九场02

    本题花式A法可以看这里

    树上套个主席树

    #include <map>
    #include <vector>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    const int N = 1e5 + 7;
    typedef long long LL;
    LL gift[N], Rank[N];//节点权值和离散化
    
    struct ChairTree{
        #define sum(x) tree[x].sum
        #define lson tree[rt].lc, tree[rt1].lc, l, m
        #define rson tree[rt].rc, tree[rt1].rc, m+1, r
        struct node{
            int lc, rc;
            LL sum;
        } tree[N * 30];
        int n, root[N], cnt;
    
        inline void build(int _n){
            n = _n; cnt = 0;
        }
    
        void add(int pos, LL val, int &rt, int rt1, int l, int r){
            tree[rt = ++cnt] = tree[rt1];
            tree[rt].sum += val;
            if (l == r) return;
            int m = (l + r) >> 1;
            if (pos <= m) add(pos, val, lson);
            else add(pos, val, rson);
        }
    
        LL query(int L, int R, int rt, int rt1, int l, int r){
            if (L <= l && r <= R) return sum(rt1) - sum(rt);
            if (sum(rt1) == 0) return 0;
            if (sum(rt1) == sum(rt)) return 0;
            LL ans = 0;
            int m = (l + r) >> 1;
            if (L <= m) ans += query(L, R, lson);
            if (m <  R) ans += query(L, R, rson);
            return ans;
        }
        #undef sum(x)
        #undef lson
        #undef rson
    } T;
    
    struct graph{
        struct Edge{
            int from, to, nxt;
            Edge(){}
            Edge(int u, int v, int n):from(u), to(v), nxt(n){}
        } edges[N * 2];
        static const int LCADEP = 17;
        int n, E, head[N];
        int top, dep[N], fa[N][LCADEP + 1];
    
        inline void AddEdge(int f, int t){
            edges[++E] = Edge(f, t, head[f]);
            head[f] = E;
        }
        inline void Init(int n){
            this -> n = n ; E = -1; top = 0; dep[0] = 0;
            for (int i = 0; i <= n; i++) head[i] = -1;
            memset(fa, 0, sizeof(fa));
        }
    
        void dfs(int u, int pre){
            T.add(gift[u], Rank[gift[u]], T.root[u], T.root[pre], 1, T.n);
            fa[u][0] = pre;
            dep[u] = dep[pre] + 1;
            for (int i = 1; i <= LCADEP; i++){
                if (dep[u] < (1<<i)) break;
                fa[u][i] = fa[fa[u][i-1]][i-1];
            }
            for (int i = head[u]; i != -1; i = edges[i].nxt){
                if (edges[i].to != pre) dfs(edges[i].to, u);
            }
        }
    
        int lca(int x, int y){
            if (dep[x] < dep[y]) swap(x,y);
            int t = dep[x] - dep[y];
            for (int i = 0; i <= LCADEP; i++) if ((1<<i) & t) x = fa[x][i];
            for (int i = LCADEP; i >= 0; i--) if (fa[x][i] != fa[y][i]){
                x = fa[x][i]; y = fa[y][i];
            }
            return x==y ? x : fa[x][0];
        }
    
        LL query(int u, int v, int L, int R){
            int f = lca(u, v);
            LL ans = 0;
            ans += T.query(L, R, T.root[f], T.root[u], 1, T.n);
            ans += T.query(L, R, T.root[fa[f][0]], T.root[v], 1, T.n);
            return ans;
        }
    } g ;
    
    int main () {
        //freopen("in.txt", "r", stdin);
        int n, q, u, v;
        for (LL a, b; ~scanf("%d%d", &n, &q);) {
            for(int i = 1; i <= n; i++) {
                scanf("%lld", &gift[i]);
                Rank[i] = gift[i];
            }
            sort(Rank + 1, Rank + n+1);
            int un = unique(Rank + 1, Rank + n+1) - (Rank+1);
            for (int i = 1; i <= n; i++){
                gift[i] = lower_bound(Rank + 1, Rank + un+1, gift[i]) - Rank;
            }
    
            g.Init(n);
            for(int i = 0; i < n - 1; i++) {
                scanf("%d%d", &u, &v);
                g.AddEdge(u, v);
                g.AddEdge(v, u);
            }
            T.build(un);
            g.dfs(1, 0);
    
            for (; q--;){
                scanf("%d%d%lld%lld", &u, &v, &a, &b);
                int aa = lower_bound(Rank+1, Rank + un+1, a) - Rank;
                if (Rank[aa] < a) aa++;
                int bb = lower_bound(Rank+1, Rank + un+1, b) - Rank;
                if (bb > un || Rank[bb] > b) bb--;
                printf("%lld", g.query(u, v, aa, bb));
                putchar(q==0 ? '
    ' : ' ');
            }
        }
        return 0;
    }
    

    hdu5919

    看了这个题解写的

    题意

    有长度为n的序列,强制在线询问[l,r] 这段区间中所有不同数出现的第一个位置,按照位置从小到大排完序以后的中间(向上取整)的那个位置是多少?

    真-语文题

    没有对原来数据的离散化操作,每棵线段树就是原数组的位置

    每个数字只有一次,每次+1,前面有了就吧前面的-1

    for的时候最坏要update 2*n次,所以要开40*n的大小

    这里写图片描述

    这里写图片描述

    # include <cstdio>
    # include <cstring>
    # include <iostream>
    # include <algorithm>
    using namespace std;
    const int N = 2e5 + 7;
    int n, arr[N], last[N];
    
    struct ChairTree{
        #define lson tree[rt].lc, tree[rt1].lc, l, m
        #define rson tree[rt].rc, tree[rt1].rc, m+1, r
        struct node{
            int lc, rc, w;
            node(){}
        } tree[N * 40];
        int root[N], cnt;
    
        inline void build(){
            root[0] = root[n+1] = cnt = 0;
            memset(tree, 0, sizeof(tree));
            memset(root, 0, sizeof(root));
        }
    
        void add(int pos, int val, int &rt, int rt1, int l, int r){
            int tmp = rt;
            tree[rt = ++cnt] = tmp ? tree[tmp] : tree[rt1];
            tree[rt].w += val;
            if (l == r) return;
            int m = (l + r) >> 1;
            if (pos <= m) add(pos, val, lson);
            else add(pos, val, rson);
        }
    
        //下面两个函数, rt==rt1, 带两个仅仅是为了凑个lson和rson的参数
    
        int sum(int L, int R, int rt, int rt1, int l, int r){
            if (L <= l && r <= R) return tree[rt].w;
            int ans = 0;
            int m = (l + r) >> 1;
            if (L <= m) ans += sum(L, R, lson);
            if (m <  R) ans += sum(L, R, rson);
            return ans;
        }
    
        int query(int k, int rt, int rt1, int l, int r){
            if (l == r) return l;
            int lsize = tree[tree[rt].lc].w;
            int m = (l + r) >> 1;
            if (lsize >= k) return query(k, lson);
            else return query(k - lsize, rson);
        }
    } T;
    
    int main(){
        //freopen("in.txt","r",stdin);
        int _, __, l, r, q;
        scanf("%d", &__);
        for (int _ = 1; _ <= __; _++){
            printf("Case #%d:", _);
            scanf("%d%d", &n, &q);
            for (int i = 1; i <= n; i++) scanf("%d", &arr[i]);
            T.build();
            memset(last, 0, sizeof(last));
            for (int i = n; i >= 1; i--){
                T.add(i, 1, T.root[i], T.root[i+1], 1, n);
                if (last[arr[i]]) T.add(last[arr[i]], -1, T.root[i], T.root[i], 1, n);
                last[arr[i]] = i;
            }
            int ans = 0;
            for (; q--;){
                scanf("%d%d", &l, &r);
                l = (l + ans) % n + 1;
                r = (r + ans) % n + 1;
                if (l > r) swap(l, r);
                int sum = T.sum(l, r, T.root[l], T.root[l], 1, n);
                ans = T.query((sum+1)/2, T.root[l], T.root[l], 1, n);
                printf(" %d", ans);
            }
            puts("");
        }
        return 0;
    }
  • 相关阅读:
    Sizzle选择器引擎介绍
    from、includes、indexOf
    indexOf与includes的区别
    ES6 find 和 filter 的区别
    Spring MVC多个视图解析器及优先级
    Spring MVC多个视图解析器及优先级
    freemarker 中文乱码问题解决办法
    freemarker 中文乱码问题解决办法
    freemarker 中文乱码问题解决办法
    Spring集成MyBatis 通用Mapper以及 pagehelper分页插件
  • 原文地址:https://www.cnblogs.com/cww97/p/12349346.html
Copyright © 2020-2023  润新知