zoukankan      html  css  js  c++  java
  • BZOJ3932 主席树

    https://www.lydsy.com/JudgeOnline/problem.php?id=3932

    题意:给出一些带有等级的线段,求一点上前K小个等级线段的等级之和

    询问是对于每一个点询问前K小的和,比较容易想到的是对每一个点都建立一颗权值线段树,维护点的数量和点的等级和。

    问题是空间太大,即使动态开点也远远不够,所以考虑用主席树来优化。

    由于主席树和前缀和密切相关的特性,我们可以考虑用差分,每一个点T[i]代表这个点的权值线段树,对于一条线段,在S[i]出加上,E[i] + 1处减去,在建立主席树的同时就可以维护出所有点的权值线段树,直接查询即可。

    注意:一看数据范围是要离散化的,但是如果去重之后,在权值线段树上取前K个就会遇到一个相同的点上有K + 1个这样的情况,这种情况可以考虑return sum / cnt * k,也可以选择不去重。

    #include <map>
    #include <set>
    #include <ctime>
    #include <cmath>
    #include <queue>
    #include <stack>
    #include <vector>
    #include <string>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <sstream>
    #include <iostream>
    #include <algorithm>
    #include <functional>
    using namespace std;
    #define For(i, x, y) for(int i=x;i<=y;i++)  
    #define _For(i, x, y) for(int i=x;i>=y;i--)
    #define Mem(f, x) memset(f,x,sizeof(f))  
    #define Sca(x) scanf("%d", &x)
    #define Sca2(x,y) scanf("%d%d",&x,&y)
    #define Sca3(x,y,z) scanf("%d%d%d",&x,&y,&z)
    #define Scl(x) scanf("%lld",&x);  
    #define Pri(x) printf("%d
    ", x)
    #define Prl(x) printf("%lld
    ",x);  
    #define CLR(u) for(int i=0;i<=N;i++)u[i].clear();
    #define LL long long
    #define ULL unsigned long long  
    #define mp make_pair
    #define PII pair<int,int>
    #define PIL pair<int,long long>
    #define PLL pair<long long,long long>
    #define pb push_back
    #define fi first
    #define se second 
    typedef vector<int> VI;
    int read(){int x = 0,f = 1;char c = getchar();while (c<'0' || c>'9'){if (c == '-') f = -1;c = getchar();}
    while (c >= '0'&&c <= '9'){x = x * 10 + c - '0';c = getchar();}return x*f;}
    const double eps = 1e-9;
    const int maxn = 1e5 + 10;
    const int INF = 0x3f3f3f3f;
    const int mod = 1e9 + 7; 
    int N,M,K;
    LL Hash[maxn];
    struct Task{
        LL S,E,P;
        Task(){}
        Task(LL S,LL E,LL P):S(S),E(E),P(P){}
    }task[maxn];
    vector<int>Q[2][maxn];
    struct Tree{
        int lt,rt;
        LL cnt,sum;
    }tree[maxn * 50];
    int T[maxn],tot;
    void newnode(int &t){
        t = ++tot;
        tree[t].cnt = tree[t].sum = 0;
    }
    void Build(int &t,int l,int r){
        newnode(t);
        if(l == r) return;
        int m = l + r >> 1;
        Build(tree[t].lt,l,m);
        Build(tree[t].rt,m + 1,r);
    }
    void update(int &t,int pre,int l,int r,LL p,LL flag){
        newnode(t);
        tree[t] = tree[pre];
        tree[t].sum += Hash[p] * flag; tree[t].cnt += flag;
        if(l == r) return;
        int m = l + r >> 1;
        if(p <= m) update(tree[t].lt,tree[pre].lt,l,m,p,flag);
        else update(tree[t].rt,tree[pre].rt,m + 1,r,p,flag);
    }
    LL query(int t,int l,int r,int k){
        if(l == r) return Hash[l];
        int m = l + r >> 1;
        int num = tree[tree[t].lt].cnt;
        if(num >= k) return query(tree[t].lt,l,m,k);
        else return query(tree[t].rt,m + 1,r,k - num) + tree[tree[t].lt].sum;
    }
    bool cmp(Task a,Task b){
        return a.P < b.P;
    }
    int main(){
        Sca2(M,N);
        for(int i = 1; i <= M ; i ++){
            LL S = read(),E = read(),P = read();
            task[i] = Task(S,E,P);
            Hash[i] = P;    
        }
        sort(Hash,Hash + 1 + M);
        sort(task + 1,task + 1 + M,cmp);
        for(int i = 1; i <= M ; i ++){
            LL S = task[i].S,E = task[i].E,P = task[i].P;
            Q[0][S].pb(i);
            Q[1][E + 1].pb(i);
        }
        Build(T[0],1,M);
        for(int i = 1; i <= N + 1; i ++){
            int pre = T[i] = T[i - 1];
            for(int j = 0 ; j < Q[0][i].size(); j ++){
                int v = Q[0][i][j];
                update(T[i],pre,1,M,v,1);
                pre = T[i];
            }
            for(int j = 0 ; j < Q[1][i].size(); j ++){
                int v = Q[1][i][j];
                update(T[i],pre,1,M,v,-1);
                pre = T[i];
            }
        }
        LL Pre = 1;
        for(int i = 1; i <= N ; i ++){
            LL X = read(),A = read(),B = read(),C = read();
            LL K = (A * Pre + B) % C + 1;
            if(K >= tree[T[X]].cnt) Pre = tree[T[X]].sum;
            else Pre = query(T[X],1,M,K);
            Prl(Pre);
        } 
        return 0;
    }
  • 相关阅读:
    java_web连接SQL_server详细步骤
    探索需求-设计前的质量之二
    EF三种编程方式详细图文教程(C#+EF)之Code First
    EF三种编程方式详细图文教程(C#+EF)之Model First
    EF三种编程方式详细图文教程(C#+EF)之Database First
    探索需求-设计前的质量之一
    编写有效用例之三
    编写有效用例之二
    golang 环境安装
    golang 命令详解
  • 原文地址:https://www.cnblogs.com/Hugh-Locke/p/10415800.html
Copyright © 2011-2022 走看看