0
点赞
收藏
分享

微信扫一扫

AtCoder Beginner Contest 242——Range Pairing Query

张宏涛心理 2022-03-11 阅读 58
算法

莫队模板题:

 在该区间内,成对条件就是cnt[x]%2==0也就是这个数x出现的次数是偶数,否则就不成对ans--。

	#include<bits/stdc++.h>
	using namespace std;
	const int maxn = 1e6;
	struct node{         //离线记录查询操作
	  int L, R, k;       //k:查询操作的原始顺序
	}q[maxn];
	int pos[maxn];
	int ans[maxn];
	int cnt[maxn];       //cnt[i]: 统计数字i出现了多少次
	int a[maxn];
	bool cmp(node a, node b){
		//按块排序,就是莫队算法:
		if(pos[a.L] != pos[b.L])        //按L所在的块排序,如果块相等,再按R排序
			return pos[a.L] < pos[b.L];
		if(pos[a.L] & 1)   return a.R > b.R; //奇偶性优化,如果删除这一句,性能差一点
		return a.R < b.R;     
			/*如果不按块排序,而是直接L、R排序,就是普通暴力法:
			if(a.L==b.L)  return a.R < b.R;
	    	return a.L < b.L;   */
	}
	int ANS = 0;
	void add(int x){     //扩大区间时(L左移或R右移),增加数x出现的次数
	    cnt[a[x]]++;
	    if(cnt[a[x]]%2==0)  ANS++;   //这个元素第1次出现
	}
	void del(int x){     //缩小区间时(L右移或R左移),减少数x出现的次数
	    cnt[a[x]]--;
	    if(cnt[a[x]]&1)  ANS--;   //这个元素消失了
	}
	int main(){	
	    int n; scanf("%d",&n);
	    int block = sqrt(n);         //每块的大小
	    for(int i=1;i<=n;i++){
	        scanf("%d",&a[i]);       //读第i个元素
			pos[i]=(i-1)/block + 1;  //第i个元素所在的块
	    }
	    int m; scanf("%d",&m);          
	    for(int i=1;i<=m;i++){       //读取所有m个查询,离线处理
	        scanf("%d%d",&q[i].L, &q[i].R);
	        q[i].k = i;              //记录查询的原始顺序
	    }
	    sort(q+1, q+1+m, cmp);       //对所有查询排序
		int L=1, R=0;                //左右指针的初始值。思考为什么?
	    for(int i=1;i<=m;i++){
	       	while(L<q[i].L)  del(L++);    //{del(L); L++;}  //缩小区间:L右移
	        while(R>q[i].R)  del(R--);    //{del(R); R--;}  //缩小区间:R左移
			while(L>q[i].L)  add(--L);    //{L--; add(L);}  //扩大区间:L左移
	        while(R<q[i].R)  add(++R);    //{R++; add(R);}  //扩大区间:R右移
	        ans[q[i].k] = ANS;
	    }
	    for(int i=1;i<=m;i++)   printf("%d\n",ans[i]);  //按原顺序打印结果
	    return 0;
	}
举报

相关推荐

0 条评论