曾记否,到中流击水,浪遏飞舟。|

Moyyer_suiy

园龄:2年7个月粉丝:4关注:18

静态区间数颜色问题

P1972 [SDOI2009] HH的项链

我知道这是很典的题,但是看提交记录发现我是今年 1 月做的,居然一点印象也没有。

看题解(洛谷第一篇)居然看懂了,比较开心。之前都是随便看看然后就开始贺题解,感觉思考的比较少,这次是看着推导过程写出来了。

思路:对于询问多个区间 [L,R] 中出现不同数字个数,当 R 相同时,如果区间出现了重复数字,那么我们只需要关心最右端的这个数字就可以了。换言之,重复出现的数字在左端将无任何贡献。例如 1 2 3 1 4,在询问 [1,4] 时,第一个 1 无任何贡献,并且当询问的 R 不断右移的过程中,第一个 1 都无任何意义,被第四位置的替代掉。

于是把询问离线下来,按照询问的右端点排序。

当出现一个数字时,如果这个数字曾经出现,则 insert(lst[pos[i]],-1),把这个数在上一个位置的标记清掉,insert(pos[i],1) 来更新这个数字的新位置。

用树状数组单点修改、区间查询,常数、空间都较小。用前缀和 query(R)-query(L-1) 把这一段的数字数出来。

#include<bits/stdc++.h>
const int N=1e6+10;
using namespace std;
int n,Q;
int a[N],t[N];
int lst[N],ans[N];
struct node{int L,R,id;}q[N];
bool cmp(node x,node y){
	return x.R<y.R;
}
int lowbit(int x){
	return x&(-x);
}
void insert(int x,int v){
	while(x<=n){
		t[x]+=v;
		x+=lowbit(x);
	}
}
int query(int x){
	int res=0;
	while(x){
		res+=t[x];
		x-=lowbit(x);
	}
	return res;
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	scanf("%d",&Q);
	for(int i=1;i<=Q;i++){
		scanf("%d%d",&q[i].L,&q[i].R);
		q[i].id=i;
	}
	sort(q+1,q+Q+1,cmp);
	for(int i=1,top=1;i<=n;i++){
		if(lst[a[i]]) insert(lst[a[i]],-1);
		insert(i,1);
		lst[a[i]]=i;
		while(top<=Q&&q[top].R==i){
			ans[q[top].id]=query(q[top].R)-query(q[top].L-1);
			top++;
		}
	}
	for(int i=1;i<=Q;i++) printf("%d\n",ans[i]);
	return 0;
}

cf 703D Mishka and Interesting sum

求区间内出现次数为偶数次的数的异或值。

考虑:一个数异或两次为 0。

则所求答案为区间所有出现过的数区间异或值的异或值。这样,所有出现过奇数次的数都会被异或掉(变成 0),出现过偶数次的数会被异或掉后再异或出来。即为答案。

维护情况和上一题一样。区间异或值直接用前缀和统计,出现过的数统计下来用树状数组维护。注意 a_i <=1e9 于是要离散化。

维护的过程中,在这个位置 insert;再将数字 x 上一次出现的位置 lst[x] 处变为 0,即再异或上一个自己就能实现。

Code
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
int n,Q;
int a[N],s[N],b[N],tot;
map<int,int> vis;
int t[N],ans[N],lst[N];
struct node{int L,R,id;}q[N];
bool cmp(node x,node y){
	return x.R<y.R;
}
int lowbit(int x){
	return x&(-x);
}
void insert(int x,int v){
	while(x<=n){
		t[x]^=v;
		x+=lowbit(x);
	}
}
int query(int x){
	int res=0;
	while(x){
		res^=t[x];
		x-=lowbit(x);
	}
	return res;
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
		s[i]=s[i-1]^a[i];
		if(!vis[a[i]]){
			b[++tot]=a[i];
			vis[a[i]]=tot;
			a[i]=tot;
		}
		else a[i]=vis[a[i]];
	}
	scanf("%d",&Q);
	for(int i=1;i<=Q;i++){
		scanf("%d%d",&q[i].L,&q[i].R);
		q[i].id=i;
	}
	sort(q+1,q+Q+1,cmp);
	for(int i=1,top=1;i<=n;i++){
		int t=a[i];
		if(lst[t]) insert(lst[t],b[a[i]]);
		insert(i,b[a[i]]);
		lst[t]=i;
		while(top<=Q&&q[top].R==i){
			ans[q[top].id]=query(q[top].R)^query(q[top].L-1)^s[q[top].R]^s[q[top].L-1];
			top++;
		}
	}
	for(int i=1;i<=Q;i++) printf("%d\n",ans[i]);
	return 0;
}

本文作者:Moyyer_suiy

本文链接:https://www.cnblogs.com/Moyyer-suiy/p/18500948

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   Moyyer_suiy  阅读(87)  评论(0编辑  收藏  举报
历史上的今天:
2023-10-24 鲜花 - 1
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起