2019.8.3 [HZOI]NOIP模拟测试12 B. 数颜色

2019.8.3 [HZOI]NOIP模拟测试12 B. 数颜色

全场比赛题解:https://pan.baidu.com/s/1eSAMuXk
数据结构学傻的做法:
对每种颜色开动态开点线段树直接维护
操作一区间查询 操作二转化为单点修改
常数有点大,需要稍微卡常。

正解:
对每种颜色开vector存储出现位置(下标),可以发现每种颜色出现位置满足单调性,操作一直接二分找到这段区间,操作二找到两个位置修改。

Code:

#include <bits/stdc++.h>
using namespace std;
const int N=6e7+5;
int n,m,tot,ans,a[N],rt[N],ls[N],rs[N],sum[N];
#define mid ((l+r)>>1)
void In(int &num){
	register char c=getchar();
	for(num=0;!isdigit(c);c=getchar());
	for(;isdigit(c);num=num*10+c-48,c=getchar()); 
}
void add(int &p,int l,int r,int pos,int val){
	if(!p) p=++tot; sum[p]+=val;
	if(l!=r) pos<=mid?add(ls[p],l,mid,pos,val):add(rs[p],mid+1,r,pos,val);
}
void query(int p,int l,int r,int L,int R){
	if(!p) return;
	if(L<=l&&r<=R) return (void) (ans+=sum[p]);
	if(L<=mid&&ls[p]&&sum[ls[p]]>0) query(ls[p],l,mid,L,R);
	if(R>mid&&rs[p]&&sum[rs[p]]>0) query(rs[p],mid+1,r,L,R);
}
int main(){
	In(n);In(m);
	for(register int i=1;i<=n;++i){
		In(a[i]);++a[i];
		add(rt[a[i]],1,n,i,1);
	}
	for(register int i=1,op,l,r,c,pos;i<=m;++i){
		In(op);
		if(op==1) {
			ans=0;
			In(l);In(r);In(c);++c;
			query(rt[c],1,n,l,r);
			printf("%d
",ans);
		}
		else {
			In(pos);
			add(rt[a[pos]],1,n,pos,-1);
			add(rt[a[pos]],1,n,pos+1,1);
			add(rt[a[pos+1]],1,n,pos+1,-1);
			add(rt[a[pos+1]],1,n,pos,1);
			swap(a[pos],a[pos+1]);
		}
	}
	return 0;
}
原文地址:https://www.cnblogs.com/yu-xing/p/11295512.html