[洛谷P3939]:数颜色(二分)

题目传送门


题目描述

小$C$的兔子不是雪白的,而是五彩缤纷的。每只兔子都有一种颜色,不同的兔子可能有相同的颜色。小$C$把她标号从$1$到$n$的$n$只兔子排成长长的一排,来给他们喂胡萝卜吃。排列完成后,第$i$只兔子的颜色是$a_i$。
俗话说得好,“萝卜青菜,各有所爱”。小$C$发现,不同颜色的兔子可能有对胡萝卜的不同偏好。比如,银色的兔子最喜欢吃金色的胡萝卜,金色的兔子更喜欢吃胡萝卜叶子,而绿色的兔子却喜欢吃酸一点的胡萝卜……为了满足兔子们的要求,小$C$十分苦恼。所以,为了使得胡萝卜喂得更加准确,小$C$想知道在区间$[l_j,r_j]$里有多少只颜色为$c_j$的兔子。不过,因为小$C$的兔子们都十分地活跃,它们不是很愿意待在一个固定的位置;与此同时,小$C$也在根据她知道的信息来给兔子们调整位置。所以,有时编号为$x_j$和$x_{j+1}$的两只兔子会交换位置。
小$C$被这一系列麻烦事给难住了。你能帮帮她吗?


输入格式

输入第$1$行两个正整数$n,m$。
输入第$2$行$n$个正整数,第$i$个数表示第$a_i$只兔子的颜色 。
输入接下来$m$行,每行为以下两种中的一种:
“$1\ l_j\ r_j\ c_j$”:询问在区间$[l_j,r_j]$里有多少只颜色为$c_j$的兔子;
“$2\ x_j$:$x_j$和$x_{j+1}$两只兔子交换了位置。


输出格式

对于每个$1$操作,输出一行一个正整数,表示你对于这个询问的答案。


样例

样例输入1:

6 5
1 2 3 2 3 3
1 1 3 2
1 4 6 3
2 3
1 1 3 2
1 4 6 3

样例输出1:

1
2
2
3

样例输入2:

10 9
1 2 3 4 5 6 1 2 3 4
1 1 3 3
1 4 6 3
2 3
1 1 3 3
1 4 6 3
1 1 10 4
1 1 10 3
1 1 10 2
1 1 10 1

样例输出2:

1
0
0
1
2
2
2
2


数据范围与提示

样例1说明:

前两个$1$操作和后两个$1$操作对应相同;在第三次的$2$操作后,$3$号兔子和$4$号兔子交换了位置,序列变为$1\ 2\ 2\ 3\ 3\ 3$。

数据范围:

$n\leqslant 3\times {10}^5$。

$1$操作$\leqslant 3\times {10}^5$。

$2$操作$\leqslant 3\times {10}^5$。

$a_i,c_i\leqslant e\times {10}^5$。


题解

$30%$算法:

啥也甭管,暴力搞就好了。

时间复杂度:$\Theta(n\times m)$。

期望得分:$30$分(朴素),$60$分($luoguO2+$卡常)

$65%$算法:

树套树。

时间复杂度:$\Theta(n\log^2n)$。

带修莫队。

时间复杂度:$\Theta(n^{\frac{5}{3}})$。

期望得分:$60~100$分。

$100%$算法:

记录每种颜色的每个兔子的出现位置,然后进行二分查找答案,操作$2$只需要改变坐标即可。

需要注意的是,如果交换的两个兔子颜色一样不要交换它们,否则会导致坐标的无序。

时间复杂度:$\Theta(n\log n)$。

期望得分:$100$分。


代码时刻

$30%$算法(朴素):

#include<bits/stdc++.h>
using namespace std;
int n,m;
int a[300001];
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)scanf("%d",&a[i]);
	while(m--)
	{
		int opt;
		scanf("%d",&opt);
		if(opt==1)
		{
			int l,r,c,ans=0;
			scanf("%d%d%d",&l,&r,&c);
			for(int i=l;i<=r;i++)
				if(a[i]==c)ans++;
			printf("%d\n",ans);
		}
		else
		{
			int x;
			scanf("%d",&x);
			swap(a[x],a[x+1]);
		}
	}
	return 0;
}

$30%$算法($luoguO2$+卡常):

// luogu-judger-enable-o2
#include<bits/stdc++.h>
#pragma GCC optimize(s)
using namespace std;
int n,m;
int a[300001];
int main()
{
	scanf("%d%d",&n,&m);
	for(register int i=1;i<=n;i++)scanf("%d",&a[i]);
	while(m--)
	{
		register int opt;
		scanf("%d",&opt);
		if(opt==1)
		{
			register int l,r,c,ans=0;
			scanf("%d%d%d",&l,&r,&c);
			for(register int i=l;i<=r;i++)
				if(a[i]==c)ans++;
			printf("%d\n",ans);
		}
		else
		{
			register int x;
			scanf("%d",&x);
			swap(a[x],a[x+1]);
		}
	}
	return 0;
}

$100%$算法:

#include<bits/stdc++.h>
using namespace std;
int n,m,a[300001];
vector<int> v[300001];
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
		v[a[i]].push_back(i);
	}
	while(m--)
	{
		int opt;
		scanf("%d",&opt);
		if(opt==1)
		{
			int l,r,c;
			scanf("%d%d%d",&l,&r,&c);
			printf("%d\n",upper_bound(v[c].begin(),v[c].end(),r)-lower_bound(v[c].begin(),v[c].end(),l));
		}
		else
		{
			int x;
			scanf("%d",&x);
			if(a[x]!=a[x+1])
			{
				(*lower_bound(v[a[x]].begin(),v[a[x]].end(),x))++;
				(*lower_bound(v[a[x+1]].begin(),v[a[x+1]].end(),x+1))--;
				swap(a[x],a[x+1]);
			}
		}
	}
	return 0;
}

rp++

猜你喜欢

转载自www.cnblogs.com/wzc521/p/11295908.html
今日推荐