• BZOJ 2120:数颜色


    初始给定一个长度为n的数列,给定m次操作,每次要么询问区间[L,R]中有多少种不同的数字,要么修改一个位置的数值。

    n<=1e4,m<=1e4,ai<=1e6

    询问区间内有多少种不同的数字容易联想到主席树,这边带修改的话那么就树套树了

    先回顾一下如果不带修改怎么做,一种做法是对每个位置维护上一个跟当前有相同数字的位置pre[i],然后在区间[L,R]中查询pre值小于L的个数,即相当于把每个数字的贡献放到第一次出现在这个区间里的位置上。

    带修改的话我们需要考虑改变一个位置的数值会影响哪些位置的pre,那么我们会影响与原先数值相同的下一个位置的pre、当前位置的pre,以及与新数值相同的下一个位置的pre。

    为了快速定位这些位置,其实我们可以对每个数值维护一个set,然后在里面二分找前驱后继,STL大法好,

    然后就是相当于单点修改一些位置的pre,然后就是树套树的事了,我这边写的是树状数组套动态开点权值线段树。

    二分的时候一些临界的条件需要特判一下,可能这边写得有点丑。

    时间复杂度O(Nlog^2N)

    #include<bits/stdc++.h>
    using namespace std;
    const int maxm=1e6;
    const int maxn=1e4;
    set<int> s[maxm+5];
    int n,m,l,r;
    int root[maxn+5];
    int pre[maxn+5],a[maxn+5];
    int lowbit(int x)
    {
        return x&(-x);
    }
    struct SegmentTree
    {
        int lc,rc;
        int cnt;
    }b[maxn<<7];
    int tot=0;
    int build()
    {
        int p=++tot;
        b[p].lc=b[p].rc=b[p].cnt=0;
        return p;
    }
    void pushup(int p)
    {
        b[p].cnt=b[b[p].lc].cnt+b[b[p].rc].cnt;
    }
    void update(int &p,int l,int r,int pos,int val)
    {
        if (!p) p=build();
        if (l==r) {
            b[p].cnt+=val;
            return ;
        }
        int mid=(l+r)>>1;
        if (pos<=mid) update(b[p].lc,l,mid,pos,val);
        else update(b[p].rc,mid+1,r,pos,val);
        pushup(p);
    }
    int getLessCnt(int p,int l,int r,int val)
    {
        if (!p) return 0;
        if (l==r) {
            if (l<val) return b[p].cnt;
            return 0;
        }
        int mid=(l+r)>>1;
        if (val<=mid) return getLessCnt(b[p].lc,l,mid,val);
        else return b[b[p].lc].cnt+getLessCnt(b[p].rc,mid+1,r,val);
    }
    char str[10];
    int main()
    {
        scanf("%d%d",&n,&m);
        for (int i=1;i<=n;i++) {
            scanf("%d",&a[i]);
            if (s[a[i]].size()) pre[i]=(*s[a[i]].rbegin());
            s[a[i]].insert(i);
        }
        for (int i=1;i<=n;i++)
            for (int j=i;j<=n;j+=lowbit(j)) update(root[j],0,n,pre[i],1);
        while (m--) {
            scanf("%s",str);
            if (str[0]=='Q') {
                scanf("%d%d",&l,&r);
                int t=0;
                for (int j=r;j;j-=lowbit(j)) t+=getLessCnt(root[j],0,n,l);
                for (int j=l-1;j;j-=lowbit(j)) t-=getLessCnt(root[j],0,n,l);
                printf("%d
    ",t);
            }
            else {
                scanf("%d%d",&l,&r);
                s[a[l]].erase(l);
                set<int>::iterator it1=lower_bound(s[a[l]].begin(),s[a[l]].end(),l);
                if (it1!=s[a[l]].end()) {
                    int p1=(*it1);
                    if (it1==s[a[l]].begin()) {
                        pre[p1]=0;
                        for (int j=p1;j<=n;j+=lowbit(j)) update(root[j],0,n,l,-1);
                        for (int j=p1;j<=n;j+=lowbit(j)) update(root[j],0,n,0,1);
                    }
                    else {
                        it1--;
                        pre[p1]=(*it1);
                        for (int j=p1;j<=n;j+=lowbit(j)) update(root[j],0,n,l,-1);
                        for (int j=p1;j<=n;j+=lowbit(j)) update(root[j],0,n,(*it1),1);
                    }
                }
                set<int>::iterator it2=lower_bound(s[r].begin(),s[r].end(),l);
                if (it2!=s[r].begin()) {
                    it2--;
                    for (int j=l;j<=n;j+=lowbit(j)) update(root[j],0,n,pre[l],-1);
                    for (int j=l;j<=n;j+=lowbit(j)) update(root[j],0,n,(*it2),1);
                    pre[l]=(*it2);
                    it2++;
                }
                else {
                    for (int j=l;j<=n;j+=lowbit(j)) update(root[j],0,n,pre[l],-1);
                    for (int j=l;j<=n;j+=lowbit(j)) update(root[j],0,n,0,1);
                    pre[l]=0;
                }
                if (it2!=s[r].end()) {
                    int p1=(*it2);
                    for (int j=p1;j<=n;j+=lowbit(j)) update(root[j],0,n,pre[p1],-1);
                    for (int j=p1;j<=n;j+=lowbit(j)) update(root[j],0,n,l,1);
                    pre[p1]=l;
                }
                s[r].insert(l);
                a[l]=r;
            }
        }
        return 0;
    }
  • 相关阅读:
    Java笔记(二十一) 动态代理
    Java笔记(二十) 注解
    Java笔记(十九) 反射
    Java笔记(十八)同步和协作工具类
    Java笔记(十七) 异步任务执行服务
    Spring使用笔记(四) 面向切面的Spring
    Spring使用笔记(三) 高级装配
    Java笔记(十六)并发容器
    Java笔记(十五) 并发包
    Java笔记(十四) 并发基础知识
  • 原文地址:https://www.cnblogs.com/xyw5vplus1/p/12271060.html
Copyright © 2020-2023  润新知