题解 数颜色

传送门

我的解法:
考虑对每种颜色建立一棵线段树,显然开不下,所以采用动态开点
可以证明,空间最坏情况发生在兔子颜色均不同时,此时空间复杂度\(nlogn\)
然后单点修改,区间查询,没了
卡卡常,再加个可行性优化的话不开大时限也能过

Code:

#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 300010
#define ll long long 
#define ld long double
#define usd unsigned
#define ull unsigned long long
//#define int long long 

#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
char buf[1<<21], *p1=buf, *p2=buf;
inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n, m;
int c[N];

namespace force1{
	void solve() {
		n=read(); m=read();
		for (int i=1; i<=n; ++i) c[i]=read();
		for (int i=1,t,x,l,r; i<=m; ++i) {
			t=read();
			if (t&1) {
				l=read(); r=read(); t=read();
				int cnt=0;
				for (int j=l; j<=r; ++j) if (c[j]==t) ++cnt;
				printf("%d\n", cnt);
			}
			else {
				x=read();
				swap(c[x], c[x+1]);
			}
		}
	}
}

namespace task{
	int size, root[N], lst[N];
	struct que{
		int t, l, r, k;
		inline void build(int i) {
			t=read();
			if (t&1) {
				l=read(); r=read(); k=read();
				lst[k]=i;
			}
			else k=read();
		}
	}ques[N<<1];
	struct segment{
		int cnt, l, r, lson, rson;
		#define t(p) tree[p]
		#define cnt(p) tree[p].cnt
		#define l(p) tree[p].lson
		#define r(p) tree[p].rson
	}tree[N*45];
	inline void pushup(int p) {cnt(p)=cnt(l(p))+cnt(r(p));}
	void upd1(int& p, int l, int r, int pos) {
		if (!p) {p=++size; t(p).l=l; t(p).r=r;}
		if (l>=r) {++cnt(p); return ;}
		int mid=(l+r)>>1;
		if (pos<=mid) upd1(l(p), l, mid, pos);
		else upd1(r(p), mid+1, r, pos);
		pushup(p);
	}
	void upd2(int& p, int l, int r, int pos) {
		if (!p) {p=++size; t(p).l=l; t(p).r=r;}
		if (l>=r) {cnt(p)+=(l==pos)?-1:1; return ;}
		int mid=(l+r)>>1;
		if (pos<=mid) upd2(l(p), l, mid, pos);
		if (pos+1>mid) upd2(r(p), mid+1, r, pos);
		pushup(p);
	}
	void upd3(int& p, int l, int r, int pos) {
		if (!p) {p=++size; t(p).l=l; t(p).r=r;}
		if (l>=r) {cnt(p)+=(l==pos)?1:-1; return ;}
		int mid=(l+r)>>1;
		if (pos<=mid) upd3(l(p), l, mid, pos);
		if (pos+1>mid) upd3(r(p), mid+1, r, pos);
		pushup(p);
	}
	int query(int p, int l, int r) {
		if (l<=t(p).l&&r>=t(p).r) return cnt(p);
		int mid=(t(p).l+t(p).r)>>1, ans=0;
		if (cnt(l(p))&&l<=mid) ans+=query(l(p), l, r);
		if (cnt(r(p))&&r>mid) ans+=query(r(p), l, r);
		return ans;
	}
	
	void solve() {
		n=read(); m=read();
		for (int i=1; i<=n; ++i) c[i]=read(), upd1(root[c[i]], 1, n, i);
		for (int i=1; i<=m; ++i) ques[i].build(i);
		que* q=ques+1;
		for (int i=1,x; i<=m; ++i,++q) {
			if (q->t&1) printf("%d\n", query(root[q->k], q->l, q->r));
			else {
				x = q->k;
				if (c[x]==c[x+1]) continue;
				if (i<=lst[c[x]]) upd2(root[c[x]], 1, n, x);
				if (i<=lst[c[x+1]]) upd3(root[c[x+1]], 1, n, x);
				swap(c[x], c[x+1]);
			}
		}
	}
}

signed main()
{
	#ifdef DEBUG
	freopen("1.in", "r", stdin);
	#endif
	
	task::solve();

	return 0;
}

题解解法:
发现交换兔子并不会影响每种颜色兔子的顺序,也不会影响同种颜色兔子间的相互顺序
那就考虑把同色的兔子放在一起,每次询问二分坐标并相减
修改的时候如果被改的兔子颜色不同就二分查找到它,把坐标改了即可
「把同色的兔子放在一起」可以直接按「颜色,坐标」双关键字排序即可

Code:

#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 300010
#define ll long long 
#define ld long double
#define usd unsigned
#define ull unsigned long long
//#define int long long 

#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
char buf[1<<21], *p1=buf, *p2=buf;
inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n, m;
int cnt[N], sum[N], c[N], maxc;
struct rabbit{int col, pos; inline void build(int i) {col=c[i]; pos=i;} rabbit(){} rabbit(int p_):pos(p_){}}rab[N];
inline bool operator < (rabbit a, rabbit b) {return a.col==b.col?a.pos<b.pos:a.col<b.col;}
inline bool comp(rabbit a, rabbit b) {return a.pos<b.pos;}

signed main()
{
	#ifdef DEBUG
	freopen("1.in", "r", stdin);
	#endif
	rabbit* pr;
	
	n=read(); m=read();
	for (int i=1; i<=n; ++i) c[i]=read(), ++cnt[c[i]], maxc=max(maxc, c[i]);
	for (int i=1; i<=n; ++i) rab[i].build(i);
	for (int i=1; i<=maxc; ++i) sum[i]=sum[i-1]+cnt[i];
	sort(rab+1, rab+n+1);
	for (int i=1,t,l,r,q,x; i<=m; ++i) {
		t=read();
		if (t&1) {
			l=read(); r=read(); q=read();
			if (!cnt[q]) {puts("0"); continue;}
			printf("%d\n", upper_bound(rab+sum[q-1]+1, rab+sum[q]+1, rabbit(r), comp)-lower_bound(rab+sum[q-1]+1, rab+sum[q]+1, rabbit(l), comp));
		}
		else {
			x=read();
			//cout<<"change"<<endl;
			if (c[x]==c[x+1]) continue;
			pr = lower_bound(rab+sum[c[x]-1]+1, rab+sum[c[x]]+1, rabbit(x), comp);
			if (pr->pos==x) pr->pos=x+1;
			pr = lower_bound(rab+sum[c[x+1]-1]+1, rab+sum[c[x+1]]+1, rabbit(x+1), comp);
			if (pr->pos==x+1) pr->pos=x;
			swap(c[x], c[x+1]);
		}
	}

	return 0;
}
posted @ 2021-06-22 20:32  Administrator-09  阅读(18)  评论(0编辑  收藏  举报