Codeforces Round #136 B

Codeforces Round #136


B题和那个多校比赛的一个题目有点像,大意都是求一段序列的满足某个元素出现次数为一个固定值的个数,都差不多

我用的线段树实现的,写的太龊了

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>

using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
const int maxn=100010;
vector<int> g[maxn];
int d[maxn<<2],a[maxn],b[maxn],ans[maxn];
struct Node
{
    int l,r,id;
}q[maxn];
void update(int p,int val,int l,int r,int rt)
{
    if(l==r) { d[rt]=val;return; }
    int m=(l+r)>>1;
    if(p<=m) update(p,val,lson);
    else update(p,val,rson);
    d[rt]=d[rt<<1]+d[rt<<1|1];
}
int query(int L,int R,int l,int r,int rt)
{
    if(L<=l&&R>=r) return d[rt];
    int m=(l+r)>>1,ret1=0,ret2=0;
    if(L<=m) ret1=query(L,R,lson);
    if(R>m)  ret2=query(L,R,rson);
    return ret1+ret2;
}
int cmp(Node a,Node b)
{
    return a.r < b.r;
}
int bin(int key,int l,int r)
{
    while(l<=r)
    {
        int m=(l+r)>>1;
        if(b[m]==key) return m;
        else if(b[m]>key) r=m-1;
        else l=m+1;
    }
}
int main()
{
    int n,m,l,r;
    while(scanf("%d%d",&n,&m)==2)
    {
        for(int i=0;i<n;i++) scanf("%d",&a[i]),b[i]=a[i],g[i].clear();
        memset(d,0,sizeof(d));
        sort(b,b+n);
        int k=unique(b,b+n)-b;
        for(int i=0;i<m;i++)
        {
           scanf("%d%d",&l,&r);
           q[i].l=l-1,q[i].r=r-1;
           q[i].id=i;
        }
        sort(q,q+m,cmp);

        int cnt=0;
        for(int i=0;i<n;i++)
        {
            int p=bin(a[i],0,k-1);
            if(g[p].size()<a[i]-1){
                g[p].push_back(i);
            }else{
                g[p].push_back(i);
                int sz=g[p].size();
                update(g[p][sz-a[i]],1,0,n-1,1);
                if(sz>=a[i]+1) update(g[p][sz-a[i]-1],-1,0,n-1,1);
                if(sz>=a[i]+2) update(g[p][sz-a[i]-2],0,0,n-1,1);
            }
            while(cnt<m&&q[cnt].r==i){
                ans[q[cnt].id]=query(q[cnt].l,q[cnt].r,0,n-1,1);
                cnt++;
            }
            if(cnt==m) break;
        }
        for(int i=0;i<m;i++) printf("%d\n",ans[i]);
    }
    return 0;
}

还有其他的方法 

不过这种方法要比线段树慢很多

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>

using namespace std;
const int maxn=100010;
int chd[500][maxn],a[maxn],b[maxn],t[maxn];

int main()
{
    int n,m,l,r;
    while(scanf("%d%d",&n,&m)==2)
    {
        memset(a,0,sizeof(a));
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&t[i]);
            if(t[i]<=n) a[t[i]]++;
        }
        int tot=0;
        for(int i=1;i<=n;i++)
           if(a[i]>=i){
               b[tot]=i;
               for(int j=1;j<=n;j++) chd[tot][j]=chd[tot][j-1]+(t[j]==i);
               tot++;
           }
        while(m--){
           scanf("%d%d",&l,&r);
           int ans=0;
           for(int i=0;i<tot;i++)
              if(chd[i][r]-chd[i][l-1]==b[i]) ans++;
           printf("%d\n",ans);
        }
    }
    return 0;
}


你可能感兴趣的:(Codeforces Round #136 B)