zoukankan      html  css  js  c++  java
  • SPOJ D-query (主席树)

    题目:传送门

    思路:莫队板子题。。

    主席树变形。以往的主席树模板题都是建立可持续化权值线段树(求区间第k大,求区间小于k的数量等),而这道题需要建立可持续化的普通线段树(维护区间而非维护值域)。

    对于a[i],我们判断其之前是否出现过,如果没有,则直接在i上加个1,否则为了保证每个数字只算一次,我们在当前版本的线段树对上一次a[i]出现的位置进行-1(先开辟一条-1的链,然后在当前版本下替换的以前版本的树链,保证之前版本的线段树不受影响)。这样就能保证对于重复出现的数字,在其对应的线段树版本中,我们取最靠右的(贪心思想)。对于每一个右端点都是一个不同版本的线段树([1,x]建树)。

    那么当查询 l and r 时,只需在r端点对应版本的线段树查询区间[l,r]的和即可。

    #include<cctype>
    #include<cstring>
    #include<cstdio>
    #include<functional>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    #pragma GCC optimize(2)
    using namespace std;
    typedef long long LL;
    typedef pair<int,int> pii;
    typedef pair<double,double> pdd;
    const int N=2e5+5;
    const int inf=0x3f3f3f3f;
    const int mod=1e9+7;
    const double eps=1e-9;
    const long double pi=acos(-1.0L);
    #define ls (i<<1)
    #define rs (i<<1|1)
    #define fi first
    #define se second
    #define pb push_back
    #define mk make_pair
    #define mem(a,b) memset(a,b,sizeof(a))
    LL read()
    {
        LL x=0,t=1;
        char ch;
        while(!isdigit(ch=getchar())) if(ch=='-') t=-1;
        while(isdigit(ch)){ x=10*x+ch-'0'; ch=getchar(); }
        return x*t;
    }
    struct node{int l,r,v;}c[N*40];
    int a[N],t[N],n,m,cnt,len,root[N],last[N*10];
    
    void update(int l,int r,int pre,int &now,int pos,int w)
    {
        c[++cnt]=c[pre],c[cnt].v+=w,now=cnt;
        if(l==r) return ;
        int mid=l+r>>1;
        if(pos<=mid) update(l,mid,c[pre].l,c[now].l,pos,w);
        else update(mid+1,r,c[pre].r,c[now].r,pos,w);
    }
    int query(int l,int r,int ll,int rr,int y)
    {
        if(ll<=l&&r<=rr) return c[y].v;
        int mid=l+r>>1,t1=0,t2=0;
        if(ll<=mid) t1=query(l,mid,ll,rr,c[y].l);
        if(rr>mid) t2=query(mid+1,r,ll,rr,c[y].r);
        return t1+t2;
    }
    int main()
    {
        n=read();
        for(int i=1;i<=n;i++)
        {
            a[i]=read();
            if(last[a[i]])
            {
                int tmp;
                update(1,n,root[i-1],tmp,last[a[i]],-1);
                update(1,n,tmp,root[i],i,1);
            }
            else update(1,n,root[i-1],root[i],i,1);
            last[a[i]]=i;
        }
        m=read();
        while(m--)
        {
            int x=read(),y=read();
            printf("%d
    ",query(1,n,x,y,root[y]));
        }
        return 0;
    }
    AC代码
  • 相关阅读:
    linux c编程错误汇总
    linux 相对路径
    内存池版本4多线程可变大小对象的内存池
    2. D3DBlankWindow添加透视投影矩阵
    1. D3DBalnkWindow
    内存池版本3单线程可变大小对象的内存池
    内联函数提高程序性能
    代码优化
    STL总结
    内存池版本2单线程固定大小对象的内存池
  • 原文地址:https://www.cnblogs.com/DeepJay/p/12402965.html
Copyright © 2011-2022 走看看