1. 程式人生 > 實用技巧 >#權值線段樹#洛谷 3939 數顏色

#權值線段樹#洛谷 3939 數顏色

題目


分析

考慮按照顏色建權值線段樹,交換直接刪除再新增就可以了
如果離散化要特判不過其實不需要離散化


程式碼

#include <cstdio>
#include <cctype>
#define rr register
using namespace std;
const int N=300011;
int n,Q,w[N<<5],ls[N<<5],cnt,rs[N<<5],rt[N],a[N];
inline signed iut(){
	rr int ans=0; rr char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans;
}
inline void print(int ans){
	if (ans>9) print(ans/10);
	putchar(ans%10+48);
}
inline void update(int &k,int l,int r,int x,int y){
	if (!k) k=++cnt; w[k]+=y;
	if (l==r) return;
	rr int mid=(l+r)>>1;
	if (x<=mid) update(ls[k],l,mid,x,y);
	    else update(rs[k],mid+1,r,x,y);
}
inline signed query(int k,int l,int r,int x,int y){
	if (!k) return 0;
	if (l==x&&r==y) return w[k];
	rr int mid=(l+r)>>1;
	if (y<=mid) return query(ls[k],l,mid,x,y);
	else if (x>mid) return query(rs[k],mid+1,r,x,y);
	else return query(ls[k],l,mid,x,mid)+query(rs[k],mid+1,r,mid+1,y);
}
signed main(){
	n=iut(); Q=iut();
	for (rr int i=1;i<=n;++i) update(rt[a[i]=iut()],1,n,i,1);
	while (Q--){
		rr int o=iut();
		if (o==1){
			rr int l=iut(),r=iut(),z=iut();
			print(query(rt[z],1,n,l,r)),putchar(10);
		}else{
			rr int x=iut();
			if (a[x]==a[x+1]) continue;
			update(rt[a[x]],1,n,x,-1);
			update(rt[a[x+1]],1,n,x+1,-1);
			update(rt[a[x]],1,n,x+1,1);
			update(rt[a[x+1]],1,n,x,1);
			a[x]^=a[x+1],a[x+1]^=a[x],a[x]^=a[x+1]; 
		}
	}
	return 0;
}