2018 牛客多校第一场J

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

题意: 就是给了一个数组a,和q个查询l,r,问 a1-al,ar-an中有多少个不同的数字

题解:

     首先把数组a拷贝一份拼接起来,这样两个区间 a1~al, ar~an 就合并成一个区间 ar~al+n

    之后就是问区间上不同的数字个数,经典的题方法看这个:http://www.cnblogs.com/tian-luo/p/9338938.html

    在数组上将数字i出现最后一个位置 置为1,然后就可以树状数组区间求和了

   把询问离线处理按照r的先后排序,具体处理看代码orz

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

struct ques
{int l,r,id;
 bool operator <(const ques b)
  { return this->r<b.r;}
  
}que[100009];

int ans[100009],a[200009],last[200009],n,q;//last[i]维护数字i最后出现的位置 
int bit[200009];//树状数组,数字i最后出现的位置为1——bit[last[i]]=1;  


int main(){
  while(scanf("%d%d",&n,&q)!=EOF)
  {
     //拷贝处理
     int m=n<< 1|1;
     memset(last,0,sizeof(last));
     memset(bit,0,sizeof(bit));
     for (int i=1;i<=n;i++) scanf("%d",&a[i]),a[i+n]=a[i];
  

     //读入查询,离线排序
     for (int i = 0;i < q;i++)scanf("%d%d",&que[i].r,&que[i].l), que[i].r+=n, que[i].id=i;
	 sort(que,que+q);

	 
	 //处理查询 
	 for (int i=0,j=1;i<q;i++){
	     //更新右端
		 for (;j<=que[i].r;j++)
		     {  if(last[a[j]])   //如果a[j]之前出现过,则删除之前的1 
			         for (int k= last[a[j]];k<m ;k+=k & -k) bit[k]--;

			     //将a[j]新的最后出现的位置加到bit中 ,更新last数组
			     for (int k=j;k<m;k+=k&-k) bit[k]++; 
			     last[a[j]]=j;
			 }	
	    int t=0;
	    //区间求和,前缀相减 
	    for (int k=m;k;k-=k&-k)t+=bit[k];
	    for (int k=que[i].l-1;k;k-=k&-k)t-=bit[k];
	    ans[que[i].id]=t;
	 
	 }  	
      for (int i=0;i<q;i++)printf("%d\n",ans[i]);
  }
  return 0;
} 

猜你喜欢

转载自blog.csdn.net/hjsss3/article/details/81159047
今日推荐