• BZOJ 1878(离散化+线段树)


    题面

    传送门

    分析

    首先我们观察到区间范围较大,而区间个数较少,考虑离散化,将所有询问按照右端点进行排序
    离散化之后研究区间颜色个数变化的规律
    当我们处理到第a[i]个段时,设a[i]上一次出现的地方为last[a[i]],则last[a[i]]之前的颜色出现次数不受影响.
    首先遍历右端点范围r,用线段树维护每一位到r的区间中有多少种颜色,记为c
    则处理到第a[i]个段时,将(last[a[i]],i]区间+1
    如r=6时
    a={3,1,5,2,4,1}
    处理第6位之前c={5,4,3,2,1,0}
    last[a[6]]=2,然后将区间(2,6]+1
    c={5,5,4,3,2,1}
    此时,在询问中找右端点为r的询问[l,r],答案即为c[l]

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #define maxn 50005
    #define maxm 200005
    using namespace std;
    int n,m;
    struct node{//标准的线段树
        int l;
        int r;
        int mark;
        int v;
        int len(){
            return r-l+1;
        }
    }tree[maxn<<2];
    void push_up(int pos){
        tree[pos].v=tree[pos<<1].v+tree[pos<<1|1].v;
    }
    void build(int l,int r,int pos){
        tree[pos].l=l;
        tree[pos].r=r;
        tree[pos].mark=0;
        tree[pos].v=0;
        if(l==r){
            tree[pos].v=0;
            return;
        }
        int mid=(l+r)>>1;
        build(l,mid,pos<<1);
        build(mid+1,r,pos<<1|1);
        push_up(pos);
    }
    void push_down(int pos){
        if(tree[pos].mark){
            tree[pos<<1].mark+=tree[pos].mark;
            tree[pos<<1|1].mark+=tree[pos].mark;
            tree[pos<<1].v+=tree[pos].mark*tree[pos<<1].len();
            tree[pos<<1|1].v+=tree[pos].mark*tree[pos<<1|1].len();
            tree[pos].mark=0;
        }
    }
    void update(int L,int R,int v,int pos){
        if(L<=tree[pos].l&&R>=tree[pos].r){
            tree[pos].v+=v*tree[pos].len();
            tree[pos].mark+=v;
            return;
        }
        push_down(pos);
        int mid=(tree[pos].l+tree[pos].r)>>1;
        if(L<=mid) update(L,R,v,pos<<1);
        if(R>mid) update(L,R,v,pos<<1|1);
        push_up(pos);
    }
    int query(int L,int R,int pos){
        if(L<=tree[pos].l&&R>=tree[pos].r){
            return tree[pos].v;
        }
        push_down(pos);
        int mid=(tree[pos].l+tree[pos].r)>>1;
        int ans=0;
        if(L<=mid) ans+=query(L,R,pos<<1);
        if(R>mid) ans+=query(L,R,pos<<1|1);
        return ans;
    }
    int bin_search(int l,int r,int x,int *a){//二分查找,离散化用
        int mid;
        while(l<=r){
            mid=(l+r)>>1;
            if(a[mid]==x) return mid;
            else if(a[mid]>x) r=mid-1;
            else l=mid+1;   
        }
        return -1;
    }
    int a[maxn],b[maxn];
    int last[maxn];
    struct ask{
        int l;
        int r;
        int i;
    }q[maxm];
    int ans[maxm];
    int cmp(ask x,ask y){
        return x.r==y.r?x.l<y.l:x.r<y.r;//按右端点排序
    }
    int main(){
        int l,r;
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            b[i]=a[i];
        }
        sort(b+1,b+1+n);
        int n2=unique(b+1,b+1+n)-b-1;
        for(int i=1;i<=n;i++){
            a[i]=bin_search(1,n2,a[i],b);
        }
        scanf("%d",&m);
        for(int i=1;i<=m;i++){
            scanf("%d %d",&q[i].l,&q[i].r);
            q[i].i=i;   
        }
        sort(q+1,q+1+m,cmp);
        int cnt=1;
        build(1,n,1);
        for(int i=1;i<=n;i++){//遍历右端点i
            update(last[a[i]]+1,i,1,1);
            last[a[i]]=i;
            while(q[cnt].r==i){
                ans[q[cnt].i]=query(q[cnt].l,q[cnt].l,1);//要按排序前的顺序输出
                cnt++;
            }
            if(cnt>m) break;
        }
        for(int i=1;i<=m;i++) printf("%d ",ans[i]);
    }
  • 相关阅读:
    mac安装sublime text 3,含注册码
    shell脚本--cut命令与awk简单使用
    mac安装VMware虚拟机(含序列号)及Ubuntu系统
    伪静态与重定向--RewriteBase
    伪静态与重定向--RewriteRule
    伪静态与重定向之初体验
    shell脚本--内容查找之grep命令
    shell脚本--文件查找之find命令
    JQuery基础-- Ajax
    安装phpredis扩展
  • 原文地址:https://www.cnblogs.com/birchtree/p/9858039.html
Copyright © 2020-2023  润新知