SPOJ - DQUERY D-query 区间种类数

题目链接

题意:

给定一段区间,以及多次查询其中某段区间内的种类数。


三种做法:


离线+树状数组:

#include<bits/stdc++.h>
using namespace std;

const int maxn=1e6;
const int maxm=2222222;
int tree[maxn];
int inline lowbit(int x) {
  return x&(-x);
}

void add(int x,int val) {
    for(int i=x;i<maxn;i+=lowbit(i)) {
        tree[i]+=val;
    }
}


int query(int x) {
     int sum=0;
     for(int i=x;i;i-=lowbit(i))
     {
         sum+=tree[i];
     }
     return sum;
}



int num[maxn];


void inline read(int & ret) {
    char c;
    ret=0;
    while((c=getchar())<'0'||c>'9');
    while(c>='0'&&c<='9') {
        ret=ret*10+c-'0';c=getchar();
    }
}

struct Node{
    int l,r,index;
    bool operator < (const Node & t) const {
         return r<t.r;
     }
}nodes[maxm];

int last[maxn];
int ans[maxm];
set<pair<int,int> > st;

inline void init() {
   memset(tree,0,sizeof(tree));
   memset(last,-1,sizeof(last));
   st.clear();
}

int main()
{
    #ifdef LOCAL_DEBUG
      // freopen("test.txt","r",stdin);
    #endif
    int n,m;
    while(~scanf("%d",&n)) {
            map<int,int> mp;
    init();
    for(int i=1;i<=n;i++) {
        read(num[i]);
       // cout<<num[i]<<endl;
    }
    read(m);
    int tmpl,tmpr;
    for(int i=1;i<=m;i++) {
        read(nodes[i].l);
        read(nodes[i].r);
        nodes[i].index=i;
    }
    sort(nodes+1,nodes+1+m);
    int index=1;
    for(int i=1;index<=m&&i<=n;i++) {
        if(last[num[i]]!=-1) add(last[num[i]],-1);
        add(i,1);
//        for(int i=1;i<=n;i++) {
//            cout<<tree[i]<<' ';
//        }
      //  cout<<endl;
        last[num[i]]=i;
        while(nodes[index].r<=i&&index<=m) {
             //   cout<<"index:"<<index<<endl;
            ans[nodes[index].index]=query(nodes[index].r)-query(nodes[index].l-1);
            index++;
        }
    }
    for(int i=1;i<=m;i++) {
       printf("%d\n",ans[i]);
    }
    }
}

主席树在线:

#include<bits/stdc++.h>
using namespace std;

const int maxn=33333,maxs=2e6;
int n,q,num[maxn],last[maxs],cnt;
int rt[maxn];
struct Node
{
    int L,R,l,r,s;
} nodes[maxn*30];


inline int red()
{
    int tot=0,f=1;
    char ch=getchar();
    while (ch<'0'||'9'<ch)
    {
        if (ch=='-')
            f=-f;
        ch=getchar();
    }
    while ('0'<=ch&&ch<='9')
        tot=tot*10+ch-48,ch=getchar();
    return tot;
}

void update(int L,int R,int &now,int last,int pos,int val) {
     now=++cnt;
     nodes[now]=nodes[last];
     nodes[now].s+=val;
     if(L==R) return ;
     int mid=(L+R)>>1;
     if(mid>=pos) update(L,mid,nodes[now].l,nodes[last].l,pos,val);
     else update(mid+1,R,nodes[now].r,nodes[last].r,pos,val);
}

int query(int L,int R,int l,int root) {
     //  cout<<"L="<<L<<" R="<<R<<endl;
       if(L>=l) return nodes[root].s;
      int mid=(L+R)>>1;
      if(mid>=l) return nodes[nodes[root].r].s+query(L,mid,l,nodes[root].l);
      else return query(mid+1,R,l,nodes[root].r);

}


void init() {
    memset(nodes,0,sizeof(nodes));
    cnt=0;
    rt[0]=nodes[0].l=nodes[0].r=nodes[0].s=0;
    memset(last,0,sizeof(last));
}



int main() {
//{
//#ifdef LOCAL_DEBUG
//    freopen("test.txt","r",stdin);
//#endif
  while(~scanf("%d",&n)) {
    init();
    int tmp;
    for (int i=1; i<=n; i++)
    {
       num[i]=red();
    //   cout<<"num[i]="<<num[i]<<endl;
       if(last[num[i]]) {
           update(1,n,tmp,rt[i-1],last[num[i]],-1);
           update(1,n,rt[i],tmp,i,1);
       }
       else  update(1,n,rt[i],rt[i-1],i,1);
       last[num[i]]=i;
  //     cout<<"tree "<<i<<endl;
      // print(rt[i]);
    }
    q=red();
    while (q--)
    {
        int l=red(),r=red();
    //    cout<<l<<' '<<r<<endl;
        printf("%d\n",query(1,n,l,rt[r]));
    }
  }
}

莫队:


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值