zoukankan      html  css  js  c++  java
  • BZOJ 1878 HH的项链(主席树)

    对于该题,离线的做法是树状数组或者线段树。

    如果强制在线的话,可以用主席树做到O(mlogn)。

    考虑到这样一个性质,对于询问[l,r]出现的数字种数。其答案就是to[i]>r的数字数。 其中to[i]表示的是第i个数的下一个相同的数出现的下标,没有则=n+1.

    很幸运这个性质是满足区间减法的,也就是说对于[1,r]和[1,l-1]的to[i]域,是可以相减得到[l,r]的to[i]域的。

    于是我们可以用主席树来解决这个问题。

    对于一组询问,实际上就是求[l-1,r]这颗线段树上的区间[r+1,n+1]的出现次数总和。

    # include <cstdio>
    # include <cstring>
    # include <cstdlib>
    # include <iostream>
    # include <vector>
    # include <queue>
    # include <stack>
    # include <map>
    # include <set>
    # include <cmath>
    # include <algorithm>
    using namespace std;
    # define lowbit(x) ((x)&(-x))
    # define pi 3.1415926535
    # define eps 1e-9
    # define MOD 1000000009
    # define INF 1000000000
    # define mem(a,b) memset(a,b,sizeof(a))
    # define FOR(i,a,n) for(int i=a; i<=n; ++i)
    # define FO(i,a,n) for(int i=a; i<n; ++i)
    # define bug puts("H");
    # define lch p<<1,l,mid
    # define rch p<<1|1,mid+1,r
    # define mp make_pair
    # define pb push_back
    typedef pair<int,int> PII;
    typedef vector<int> VI;
    # pragma comment(linker, "/STACK:1024000000,1024000000")
    typedef long long LL;
    int Scan() {
        int res=0, flag=0;
        char ch;
        if((ch=getchar())=='-') flag=1;
        else if(ch>='0'&&ch<='9') res=ch-'0';
        while((ch=getchar())>='0'&&ch<='9')  res=res*10+(ch-'0');
        return flag?-res:res;
    }
    void Out(int a) {
        if(a<0) {putchar('-'); a=-a;}
        if(a>=10) Out(a/10);
        putchar(a%10+'0');
    }
    const int N=50005;
    //Code begin...
    
    int root[N], s[N*80], ls[N*80], rs[N*80], sz, vis[1000005], to[N];
    
    void insert(int l, int r, int x, int &y, int val){
        y=++sz;
        s[y]=s[x]+1;
        if (l==r) return ;
        ls[y]=ls[x]; rs[y]=rs[x];
        int mid=(l+r)>>1;
        if (val<=mid) insert(l,mid,ls[x],ls[y],val);
        else insert(mid+1,r,rs[x],rs[y],val);
    }
    int query(int l, int r, int x, int y, int L){
        if (r<L) return 0;
        if (l>=L) return s[y]-s[x];
        int mid=(l+r)>>1;
        return query(l,mid,ls[x],ls[y],L)+query(mid+1,r,rs[x],rs[y],L);
    }
    int main()
    {
        int n, m, l, r, x;
        scanf("%d",&n);
        FOR(i,1,n) {
            scanf("%d",&x);
            if (vis[x]) to[vis[x]]=i;
            vis[x]=i;
        }
        FOR(i,1,n) if (to[i]==0) to[i]=n+1;
        FOR(i,1,n) insert(1,n+1,root[i-1],root[i],to[i]);
        scanf("%d",&m);
        FOR(i,1,m) {
            scanf("%d%d",&l,&r);
            printf("%d
    ",query(1,n+1,root[l-1],root[r],r+1));
        }
        return 0;
    }
    View Code
  • 相关阅读:
    docker学习(3) 容器的启动过程
    docker学习(2) mac中docker-machine使用vmware fusion以及配置国内镜像加速
    docker学习(1) 安装
    maven/gradle 打包后自动上传到nexus仓库
    bash/shell编程学习(3)
    jenkins 入门教程(下)
    jenkins 入门教程(中)
    jenkins 入门教程(上)
    bash/shell编程学习(2)
    ssh远程执行目标机器上的命令
  • 原文地址:https://www.cnblogs.com/lishiyao/p/6634789.html
Copyright © 2011-2022 走看看