Group 2013 Multi-University Training 4
题意:给出n个从1~n的数字(唯一不重复)
给出m个区间,问区间内最少有多少个不同的小组
小组:这个区间内的数是连续的,比如:1 3 2
思路:可以考虑线段树跟莫队
我们这里用莫队来解
这里用到一个vis数组来标记是否出现过
增加某数字,就看看这个数字左右两边的数是否存在,再另作判断;
删除某数字,同上
但是有一点需要注意的是,倘若出现区间(2,3)到(4,5)这样的改变 假如我们先移动L ,就会先出现(4,3)这样一个区间,这样影响了答案的正确性
但是我们如果把有关R的移动放前面就可以了嘛?
不,假如有(4,5)到(2,3)这样的改变的话呢,我们就会造成(4,3)的局面;
所以我们需要排除这两种情况
当出现这些情况的时候呢,我们就将这个区间内的数给清空,然后add上这个区间内的一个数即可
那么这样会不会增加复杂度呢?
不会,因为即使不这样做,原本的区间也要走过这段路,所耗费的复杂度大致相同
所以,是可行的
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=2e5+10; 4 int vis[maxn]; 5 int a[maxn]; 6 int temp; //记录每一个区间的不同数的总数; 7 int block; //分块 8 int ans[maxn]; 9 struct node 10 { 11 int l,r,id; 12 }query[maxn]; 13 bool cmp(node x,node y) 14 { 15 if(x.l/block!=y.l/block) //先按L分块,从小到大分 16 return x.l<y.l; 17 if(x.l/block&1) //再按R来排序,根据该区间为奇数或是偶数, 18 return x.r<y.r; //来确定从大到小排还是从小到大 19 return x.r>y.r; 20 } 21 void add(int x) 22 { 23 if(!vis[x-1]&&!vis[x+1]) temp++; 24 if(vis[x-1]&&vis[x+1]) temp--; 25 vis[x]=1; 26 } 27 void Delete(int x) 28 { 29 if(vis[x-1]&&vis[x+1]) temp++; 30 if(!vis[x-1]&&!vis[x+1]) temp--; 31 vis[x]=0; 32 } 33 int main() 34 { 35 int T; 36 scanf("%d",&T); 37 while(T--){ 38 memset(vis,0,sizeof(vis)); 39 int n,q; 40 scanf("%d%d",&n,&q); 41 for(int i=1;i<=n;i++) scanf("%d",&a[i]); 42 for(int i=1;i<=q;i++){ 43 scanf("%d%d",&query[i].l,&query[i].r); 44 query[i].id=i; 45 } 46 block=sqrt(n); 47 sort(query+1,query+1+q,cmp); 48 int left=1,right=0; 49 temp=0; 50 for(int i=1;i<=q;i++){ 51 if(right<query[i].l){ 52 for(int k=left;k<=right;k++) 53 vis[a[k]]=0; 54 temp=1; 55 vis[a[query[i].l]]=1; 56 left=right=query[i].l; 57 } 58 if(left>query[i].r){ 59 for(int k=left;k<=right;k++) 60 vis[a[k]]=0; 61 temp=1; 62 vis[a[query[i].r]]=1; 63 left=right=query[i].r; 64 65 } 66 while(right<query[i].r)add(a[++right]); 67 while(right>query[i].r)Delete(a[right--]); 68 //同理 69 //如果左端点小于询问区间,则需要将不在区间内的点给删除 70 while(left<query[i].l) Delete(a[left++]); 71 //如果左端点大于询问区间,则需要将为纳入区间但需要纳入区间的点给加进来 72 while(left>query[i].l) add(a[--left]); 73 //同理 74 //记录答案 75 ans[query[i].id]=temp; 76 } 77 for(int i=1;i<=q;i++) 78 printf("%d\n",ans[i]); //输出答案 79 } 80 return 0; 81 }