Uva12345: Dynamic len(set(a[L:R]))

2 篇文章 0 订阅
1 篇文章 0 订阅

Uva12345: Dynamic len(set(a[L:R]))

可修改莫队 OR 线段树套树状数组 OR 分块

题解:

  • 解法1:

    可修改莫队。每块 n23 ,总复杂度 O(n53) .

    Code:

    
    #include <algorithm>
    
    
    #include <iostream>
    
    
    #include <cstring>
    
    
    #include <cstdio>
    
    
    #define D(x) cout<<#x<<" = "<<x<<"  "
    
    
    #define E cout<<endl
    
    using namespace std;
    const int mxn = 1e6+5;
    const int N = 5e4+5;
    
    int n,m,csz,qsz,bsz,cnt[mxn],ans[N],res,lpos,rpos,now,a[N],tp[N];
    
    struct Que{
    int l,r,tim,id;
    } q[N];
    
    bool cmp(const Que &a,const Que &b){
    if(a.l/bsz != b.l/bsz) return a.l/bsz < b.l/bsz;
    else return a.r<b.r || (a.r==b.r && a.tim<b.tim);
    }
    
    struct Change{
    int p,x,y,tim;
    } c[N];
    
    void ins(int p){ cnt[a[p]]++; if(cnt[a[p]]==1) res++; }
    void erase(int p){ cnt[a[p]]--; if(cnt[a[p]]==0) res--; }
    void change(int i,int op){ 
    //    printf("change: %d %d\n",i,op); 
    if(lpos<=c[i].p && c[i].p<=rpos) erase(c[i].p);
    a[c[i].p]=op?c[i].y:c[i].x;
    if(lpos<=c[i].p && c[i].p<=rpos) ins(c[i].p);
    }
    
    int main(){
    freopen("a.in","r",stdin);
    char op[5]; int x,y;
    scanf("%d%d",&n,&m);
    for(bsz=1;bsz*bsz*bsz<=n;bsz++); bsz=bsz*bsz;
    for(int i=1;i<=n;i++) scanf("%d",a+i), tp[i]=a[i];
    for(int i=1;i<=m;i++){
        scanf("%s%d%d",op,&x,&y);
        if(op[0]=='M'){ x++; c[++csz].p=x; c[csz].x=tp[x]; c[csz].y=y; c[csz].tim=i; tp[x]=y; }
        else{ x++; q[++qsz].l=x; q[qsz].r=y; q[qsz].tim=i; q[qsz].id=qsz; }
    }
    sort(q+1,q+1+qsz,cmp);
    lpos=1, rpos=0, now=0;
    for(int i=1;i<=qsz;i++){
    //        D(q[i].l); D(q[i].r); D(q[i].tim); E;
        while(lpos<q[i].l){ erase(lpos); lpos++; }
        while(lpos>q[i].l){ lpos--; ins(lpos); }
        while(rpos<q[i].r){ rpos++; ins(rpos); }
        while(rpos>q[i].r){ erase(rpos); rpos--; }
        while(now<csz && c[now+1].tim<q[i].tim){ now++; change(now,1); }
        while(now>0 && c[now].tim>q[i].tim){ change(now,0); now--; }
        ans[q[i].id]=res;
    //        D(lpos); D(rpos); D(now); E;
    //        for(int i=1;i<=n;i++)cout<<a[i]<<" "; cout<<endl;
    //        for(int i=1;i<=5;i++)cout<<cnt[i]<<" "; cout<<endl;
    }
    for(int i=1;i<=qsz;i++) printf("%d\n",ans[i]);
    }
  • 解法2:

    设pre[i]表示i前面一个和a[i]相同的字符的位置。

    答案就是长度减去pre[i]大于等于l的个数。i∈[l,r].

    就用权值BIT维护pre,每个bit节点上套一个位置的权值线段树即可。

    线段树动态开点,复杂度 O(mlog2n) .

    Code:

    
    #include <iostream>
    
    
    #include <cstring>
    
    
    #include <cstdio>
    
    
    #include <set>
    
    
    #define D(x) cout<<#x<<" = "<<x<<"  "
    
    
    #define E cout<<endl 
    
    using namespace std;
    const int mxn = 1000000;
    const int N = 50005;
    
    int n,m,a[N],pre[N],lst[N];
    int lch[N*20],rch[N*20],cnt[N*20],sz;
    set<int> s[mxn+5];
    
    void change(int &x,int p,int d,int l=1,int r=n){
    if(!x) x=++sz;
    cnt[x]+=d;
    //    printf("change: "); D(x); D(p); D(d); D(l); D(r); E;
    if(l==r) return;
    int mid=(l+r)>>1;
    if(p<=mid) change(lch[x],p,d,l,mid);
    else change(rch[x],p,d,mid+1,r);
    }
    
    int query(int x,int ql,int qr,int l=1,int r=n){
    if(!x) return 0;
    //    printf("query: "); D(x); D(ql); D(qr); D(l); D(r); E;
    if(ql<=l && r<=qr){
    //        D(cnt[x]); E;
        return cnt[x];
    }
    else{
        int mid=(l+r)>>1, ans=0;
        if(ql<=mid) ans+=query(lch[x],ql,qr,l,mid);
        if(qr>mid) ans+=query(rch[x],ql,qr,mid+1,r);
        return ans;
    }
    }
    
    struct BIT{
    void add(int x,int p,int d){
        x++; while(x<=n){ change(x,p,d); x+=x&(-x); }
    }
    int sum(int x,int ql,int qr){
        int ans=0; x++;
        while(x>0){ ans+=query(x,ql,qr); x-=x&(-x); } 
        return ans;
    }
    } bit;
    
    int Nxt(int x){
    //    D(x); D(a[x]); E;
    set<int>::iterator it=s[a[x]].find(x);
    if(++it!=s[a[x]].end()) return *it;  else return -1;
    }
    int Pre(int x){
    set<int>::iterator it=s[a[x]].find(x);
    if(it!=s[a[x]].begin()) return*(--it);  else return 0;
    }
    
    int main(){
    freopen("a.in","r",stdin);
    freopen("b.out","w",stdout);
    int x,y,nx,pr,ans; char op[5];
    scanf("%d%d",&n,&m); sz=n;
    for(int i=1;i<=n;i++) scanf("%d",a+i);
    for(int i=1;i<=n;i++){
        pre[i]=lst[a[i]]; lst[a[i]]=i;
    //        D(pre[i]); E;
    }
    for(int i=1;i<=n;i++){
    //        D(i); E;
        bit.add(pre[i],i,1);
        s[a[i]].insert(i);
    }
    //    for(int i=1;i<=n;i++){
    //        cout<<query(pre[i]+1,i,i)<<endl;
    //    }
    for(int i=1;i<=m;i++){
        scanf("%s%d%d",op,&x,&y); x++;
        if(op[0]=='M'){
            nx=Nxt(x); //D(nx); E;
            if(nx!=-1){
                bit.add(pre[nx],nx,-1);
                bit.add(pre[x],nx,1);
                pre[nx]=pre[x];
            }
            s[a[x]].erase(x); a[x]=y; s[a[x]].insert(x);
            nx=Nxt(x); //D(nx); E;
            if(nx!=-1){
                bit.add(pre[nx],nx,-1);
                bit.add(x,nx,1);
                pre[nx]=x;
            }
            pr=Pre(x); //D(pr); E;
            bit.add(pre[x],x,-1);
            bit.add(pr,x,1);
            pre[x]=pr;
        }
        else{
            ans=bit.sum(x-1,x,y);
            printf("%d\n",ans);
        }
    }
    }
  • 解法3:

    还是使用解法2的pre思想,分块,把每块中的pre排好序。

    询问:零散的直接查,整块的二分查找。

    修改:修改相应的值并不停交换相邻两个直到重新排好序。

    复杂度: O(nnlogn) .

    Code:

    //目测比较简单

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值