Kattis:Curious Cupid
题目链接:https://open.kattis.com/problems/cupid
题目大意:有$n$个男生及$n$个女生,每人懂得$1$种语言(共$k$种语言),若男生懂的语言与女生相同即可配对(一人仅可配对一次)。现有$m$个区间,问各个区间内最大的配对人数。
莫队算法
$k$的数量级为$10^6$而$m$的数量级为$10^4$,故对于每个$m$去遍历$k$是行不通的。
考虑用莫队算法,先将所有区间按$lfloorfrac{L}{sqrt{n}} floor$升序$R$升序排序。
然后用数组lang[i][2]记录区间内男生女生懂语言$i$的人数,从第一个区间开始向下一个区间转移。
总复杂度为$O(n imes sqrt{n})$.
/*每次转移以函数,代码量少且清晰;ans数组代替了重新对q数组的排序*/
代码如下:
1 #include <iostream> 2 #include <algorithm> 3 #include <cmath> 4 #define N 50005 5 #define M 50005 6 #define K 1000005 7 using namespace std; 8 int n,m,k,a[N][2],B,ans[M],lang[K][2]; 9 struct node{ 10 int l,r,id; 11 bool operator<(const node x)const{ 12 if(l/B==x.l/B)return r<x.r; 13 else return l/B<x.l/B; 14 } 15 }q[M]; 16 void des(int p,int &ans){ 17 int x=a[p][0],y=a[p][1]; 18 if(lang[x][0]<=lang[x][1])ans--; 19 lang[x][0]--; 20 if(lang[y][1]<=lang[y][0])ans--; 21 lang[y][1]--; 22 } 23 void add(int p,int &ans){ 24 int x=a[p][0],y=a[p][1]; 25 if(lang[x][0]<lang[x][1])ans++; 26 lang[x][0]++; 27 if(lang[y][1]<lang[y][0])ans++; 28 lang[y][1]++; 29 } 30 int main(void){ 31 std::ios::sync_with_stdio(false); 32 cin>>n>>m>>k; 33 B=sqrt(n); 34 for(int i=0;i<n;++i)cin>>a[i][0]; 35 for(int i=0;i<n;++i)cin>>a[i][1]; 36 for(int i=0;i<m;++i){ 37 cin>>q[i].l>>q[i].r; 38 q[i].id=i; 39 } 40 sort(q,q+m); 41 int l=q[0].l,r=q[0].r,tmp=0; 42 for(int i=l;i<=r;++i) 43 lang[a[i][0]][0]++,lang[a[i][1]][1]++; 44 for(int i=0;i<k;++i) 45 tmp+=(lang[i][0]<lang[i][1]?lang[i][0]:lang[i][1]); 46 ans[q[0].id]=tmp; 47 for(int i=1;i<m;++i){ 48 while(l<q[i].l){des(l,tmp);l++;} 49 while(l>q[i].l){l--;add(l,tmp);} 50 while(r<q[i].r){r++;add(r,tmp);} 51 while(r>q[i].r){des(r,tmp);r--;} 52 ans[q[i].id]=tmp; 53 } 54 for(int i=0;i<m;++i) 55 cout<<ans[i]<<" "; 56 }