牛客网多校比赛第一场 J-Diffient(树状数组或者莫队算法)

https://www.nowcoder.com/acm/contest/139/J

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+500;
typedef struct node{
    int l,r,No;
}node;
int cmp(node a, node b){
    return (a.r==b.r&&a.l<b.l)||a.r<b.r;
}
node q[N];
int n,m,k,tmp,c[N],a[N],vis[N],ans[N];
int lowbit(int x){return x&(-x);}
void update(int x,int val=1){for(;x<=2*n;c[x]+=val,x+=lowbit(x));}
int getsum(int x){ int ret=0;for(;x>0;ret+=c[x],x-=lowbit(x));return ret;}
int main()
{
    while(~scanf("%d%d",&n,&m)){
        memset(q,0,sizeof(q));
        memset(c,0,sizeof(c));
        memset(vis,0,sizeof(vis));
        memset(ans,0,sizeof(ans));
        for(int i=1;i<=n;i++){scanf("%d",&a[i]);a[n+i]=a[i];}
        for(int i=1;i<=m;i++){
            scanf("%d%d",&q[i].l,&q[i].r);q[i].No=i;
            tmp=q[i].r;q[i].r=q[i].l+n;q[i].l=tmp;
        }
        sort(q+1, q+1+m,cmp);
        int L=1;

        for(int i=1;i<=m;i++){
            for(int j=L;j<=q[i].r;j++){
                if(vis[a[j]]){
                    update(vis[a[j]],-1);
                }
                update(j,1);
                vis[a[j]]=j;
            }
            L=q[i].r+1;
            ans[q[i].No]=getsum(q[i].r)-getsum(q[i].l-1);
        }
        for(int i=1;i<=m;i++){
            printf("%d\n",ans[i]);
        }
    }
    return 0;
}

用莫队算法会超时,但我还是贴出来。如果预处理过的莫队还是能过。

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+50;
void read(int &ans){
    int x=0,f=1;char c=getchar();
    for( ; !isdigit(c); c=getchar()) { if(c=='-') f=-1;}
    for( ;  isdigit(c); c=getchar()) {x=x*10+c-'0';}
    ans=f*x;
}
int unit,n,m,tmp;
int num[N],a[N],ans[N];
typedef struct node{
    int L,R,No;
}node;
int cmp(node a,node b){
    return a.L/unit!=b.L/unit ? a.L/unit <b.L/unit :a.R<b.R;
}
node Q[N];
void add(int x){
    if(num[x]==0) tmp++;
    num[x]++;
}
void del(int x){
    num[x]--;
    if(num[x]==0) tmp--;
}
void solve(){
    memset(num,0,sizeof(num));
    unit=(int)pow(n,0.67);
    sort(Q+1,Q+m+1,cmp);
    int L=1,R=0;
    tmp=0;
    for(int i=1;i<=m;i++){
        while(R<Q[i].R) { add(a[++R]); }
        while(R>Q[i].R) { del(a[R--]); }
        while(L<Q[i].L) { del(a[L++]); }
        while(L>Q[i].L) { add(a[--L]); }
        ans[Q[i].No]=tmp;
    }
    for(int i=1;i<=m;i++){
        printf("%d\n",ans[i]);
    }
}
int main()
{
    while(~scanf("%d%d",&n,&m)){

        for(int i=1;i<=n;i++) {read(a[i]);a[i+n]=a[i];}
        for(int i=1;i<=m;i++){
            read(Q[i].L);
            read(Q[i].R);
            Q[i].No=i;
            tmp=Q[i].R;
            Q[i].R=Q[i].L+n;
            Q[i].L=tmp;
        }
        //sort(Q+1,Q+m+1);
        //for(int i=1;i<=m;i++)printf("%d %d\n",Q[i].L,Q[i].R);
        solve();
    }
    return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值