zoukankan      html  css  js  c++  java
  • bzoj1878: [SDOI2009]HH的项链(主席树/离线+BIT)

        这题有离线和在线两种做法。

        离线:将查询区间按左端点排序,预处理出所有数下一次的出现位置,一开始将所有第一次出现的数a[i]++,之后当扫到这个数的时候a[next[i]]++,相当于差分,给之后的位置答案+1,因为查询区间左端点排序了,所以再也查不到当前点,这个数对答案有贡献的区间只有右端点在这个数下一次出现的位置右边的区间,当扫到查询区间左端点时当前答案为sum(r)-sum(l-1)。

    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #include<queue>
    #include<cmath>
    #include<map>
    #define ll long long 
    using namespace std;
    const int maxn=500010,inf=1e9;
    struct poi{int l,r,pos;}q[maxn];
    int n,m,x,y,z,tot,N;
    int tree[maxn],a[maxn],b[maxn],ans[maxn],next[maxn],pre[maxn];
    bool v[maxn];
    inline void read(int &k)
    {
        int f=1;k=0;char c=getchar();
        while(c<'0'||c>'9')c=='-'&&(f=-1),c=getchar();
        while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();
        k*=f;
    }
    inline bool cmp(poi a,poi b){return a.l<b.l;}
    inline int lowbit(int x){return x&-x;};
    inline void add(int x){for(;x<=n;x+=lowbit(x))tree[x]++;}
    inline int query(int x){int sum=0;for(;x;x-=lowbit(x))sum+=tree[x];return sum;}
    int main()
    {
        read(n);
        for(int i=1;i<=n;i++)read(a[i]),b[i]=a[i];N=n;
        sort(b+1,b+1+N);N=unique(b+1,b+1+N)-b-1;
        for(int i=1;i<=n;i++)a[i]=lower_bound(b+1,b+1+N,a[i])-b;
        for(int i=n;i;i--)next[i]=pre[a[i]],pre[a[i]]=i;
        for(int i=1;i<=n;i++)
        if(!v[a[i]])add(i),v[a[i]]=1;
        read(m);
        for(int i=1;i<=m;i++)
        {
            read(q[i].l);read(q[i].r);
            q[i].l--;q[i].pos=i;
        }
        sort(q+1,q+1+m,cmp);
        for(int i=0,j=1;i<=n&&j<=m;i++)
        {
            if(next[i])add(next[i]);
            while(j<=m)
            {
                if(q[j].l!=i)break;
                ans[q[j].pos]=query(q[j].r)-query(q[j].l);
                j++;
            }
        }
        for(int i=1;i<=m;i++)printf("%d
    ",ans[i]);
        return 0;
    }
    View Code

        在线:预处理出所有数上一次出现的位置,把问题转化成查询区间里有多少数last[i]<l,这显然可以用主席树了

    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #include<queue>
    #include<cmath>
    #include<map>
    #define ll long long 
    using namespace std;
    const int maxn=50010,inf=1e9;
    struct poi{int sum,lt,rt;}tree[maxn*20];
    int n,m,l,r,sz,N;
    int root[maxn],pre[maxn],last[maxn],a[maxn],b[maxn];
    void read(int &k)
    {
        int f=1;k=0;char c=getchar();
        while(c<'0'||c>'9')c=='-'&&(f=-1),c=getchar();
        while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();
        k*=f;
    }
    void update(int &x,int l,int r,int cx)
    {
        tree[++sz]=tree[x];tree[sz].sum++;x=sz;
        if(l==r)return;
        int mid=(l+r)>>1;
        if(cx<=mid)update(tree[x].lt,l,mid,cx);
        else update(tree[x].rt,mid+1,r,cx);
    }
    int query(int x,int y,int l,int r,int cl,int cr)
    {
        if(cl<=l&&r<=cr)return tree[y].sum-tree[x].sum;
        int mid=(l+r)>>1,ret=0;
        if(cl<=mid)ret+=query(tree[x].lt,tree[y].lt,l,mid,cl,cr);
        if(cr>mid)ret+=query(tree[x].rt,tree[y].rt,mid+1,r,cl,cr);
        return ret;
    }
    int main()
    {
        read(n);
        for(int i=1;i<=n;i++)read(a[i]),b[i]=a[i];N=n;
        sort(b+1,b+1+N);N=unique(b+1,b+1+N)-b-1;
        for(int i=1;i<=n;i++)a[i]=lower_bound(b+1,b+1+N,a[i])-b;
        for(int i=1;i<=n;i++)pre[i]=last[a[i]],last[a[i]]=i;
        for(int i=1;i<=n;i++)update(root[i]=root[i-1],0,n,pre[i]);
        read(m);
        for(int i=1;i<=m;i++)
        {
            read(l);read(r);
            printf("%d
    ",query(root[l-1],root[r],0,n,0,l-1));
        }
    }
    View Code
  • 相关阅读:
    如何在Window上使用Git
    【坑】log4j-over-slf4j.jar AND slf4j-log4j12.jar的冲突问题
    如何查看hadoop与hbase的版本匹配关系
    为什么要用Message Queue
    Storm+kafka的HelloWorld初体验
    KafkaOffsetMonitor使用方法
    Linux虚拟机配置本地yum源
    andorid CmakeLists
    python tkinter Treeview 事件绑定
    python我的tkinter学习,玩玩
  • 原文地址:https://www.cnblogs.com/Sakits/p/7400546.html
Copyright © 2011-2022 走看看