首页 > 其他分享 >【题解】Luogu P3939 数颜色

【题解】Luogu P3939 数颜色

时间:2023-02-15 18:01:58浏览次数:44  
标签:int 题解 sum ans mid P3939 Luogu now rson

题目分析:

解法一:

显然我们可以直接对每一种颜色建一棵线段树,然后剩下的操作就非常简单了。

代码:

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N = 3e5+5;
int tot,col[N],lson[100*N],rson[100*N],sum[100*N],rt[N];
void modify(int &now,int now_l,int now_r,int pos,int val){
	if(!now)	now = ++tot;
	if(now_l == now_r){
		sum[now] += val;
		return;
	}
	int mid = (now_l + now_r)>>1;
	if(pos <= mid)	modify(lson[now],now_l,mid,pos,val);
	if(pos > mid)	modify(rson[now],mid+1,now_r,pos,val);
	sum[now] = sum[lson[now]] + sum[rson[now]];
}
int query(int now,int now_l,int now_r,int l,int r){
	if(!now)	return 0;
	if(l <= now_l && r >= now_r)	return sum[now];
	int mid = (now_l + now_r)>>1,ans = 0;
	if(l <= mid)	ans = ans + query(lson[now],now_l,mid,l,r);
	if(r > mid)		ans = ans + query(rson[now],mid+1,now_r,l,r);
	return ans;
}
int main(){
	int n,m;scanf("%d%d",&n,&m);
	for(int i=1; i<=n; i++){
		scanf("%d",&col[i]);
		modify(rt[col[i]],1,n,i,1);
	}
	for(int i=1; i<=m; i++){
		int opt,x,y,z;
		scanf("%d",&opt);
		if(opt == 1){
			scanf("%d%d%d",&x,&y,&z);
			printf("%d\n",query(rt[z],1,n,x,y));
		}
		else{
			scanf("%d",&x);y = x + 1;
			modify(rt[col[x]],1,n,x,-1);modify(rt[col[y]],1,n,y,-1);
			modify(rt[col[x]],1,n,y,1);modify(rt[col[y]],1,n,x,1);
			swap(col[x],col[y]);
		}
	}
	return 0;
}

解法二:

(大型学数据结构学傻系列)
我们其实可以考虑直接用数组储存每一种颜色出现的位置,对于查询操作就直接二分就好了。
之所以可以这样做,因为我们每一次交换位置都是交换的 \(x\) 与 \(x+1\),当它们的颜色不同时,交换是不会影响数组内的单调性的,所以就可以直接这样做了。

代码:

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N = 5e5+5;
vector<int> v[N];
int a[N];
int main(){
	int n,m;scanf("%d%d",&n,&m);
	for(int i=1; i<=n; i++){
		scanf("%d",&a[i]);
		v[a[i]].push_back(i);
	}
	for(int i=1; i<=m; i++){
		int opt,x,y,z;scanf("%d",&opt);
		if(opt == 1){
			scanf("%d%d%d",&x,&y,&z);
			int t1 = lower_bound(v[z].begin(),v[z].end(),x) - v[z].begin();
			int t2 = upper_bound(v[z].begin(),v[z].end(),y) - v[z].begin() - 1;
			printf("%d\n",t2 - t1 + 1);
		}
		else{
			scanf("%d",&x);y = x + 1;
			if(a[x] == a[y])	continue;
			int t1 = lower_bound(v[a[x]].begin(),v[a[x]].end(),x) - v[a[x]].begin();
			int t2 = lower_bound(v[a[y]].begin(),v[a[y]].end(),y) - v[a[y]].begin();
			swap(v[a[x]][t1],v[a[y]][t2]);
			swap(a[x],a[y]);
		}
	}
	return 0;
}

标签:int,题解,sum,ans,mid,P3939,Luogu,now,rson
From: https://www.cnblogs.com/linyihdfj/p/17124139.html

相关文章

  • hadoop之shuffle阶段相关面试题解析
    --思考1:map()方法写出的数据存储到哪里?                                  --内存中1、在内存中存有一个环形缓冲区,该缓冲......
  • [省选联考 2022] 填树 题解
    神奇dp。发现我看到dp大多数时候只会暴力。那我约等于退役了啊。题意:自己看。首先有一个显然的暴力。枚举一个最小值\(L\),然后区间就限定在了\([L,L+K]\)。那么普及......
  • NOIP2015 普及组 推销员题解
    原题链接给定一个数轴,数轴上有一些点,第\(i\)个点离起点的距离是\(S_i\),取走它要消耗\(A_i\)的代价,同时在数轴上每移动一格要\(1\)的代价,路线只能从数轴......
  • CSP2022 假期计划 题解
    给你一张\(n\)个点,\(m\)条边的无向图,每个点有点权,要求你在图中选出\(A\),\(B\),\(C\),\(D\)四个点,使得\(1\rightarrowA\rightarrowB\rightarrowC\righ......
  • DTOJ 2023.02.11 测试 题解
    DTOJ2023.02.11测试题解2023省选模拟Round#12\(100+8+50=158\)还行T2想到了,但是没写,我觉得写了也不一定写得出来,挺妙的T1题意http://59.61.75.5:18018/p/545......
  • 读者最需要什么样的题解
    哈哈,其实还是鲜花,主要是看到\(\text{f}\color{red}{\text{eecle6418}}\)的这篇题解有感而发,当然我自己写的题解也很抽象,需要改正。当然这里的写题解是指主动打算写一......
  • 小孩召开法 题解
    开题之前の一些废话:小孩召开法,旦写一北砬。梦厷停留在,破了大式様。——龚诗锋《炄勺,砒》小孩。又是我很不会的排列计数。而且神题。久仰大名。现在是2月13日......
  • ARC120C Swaps 2 题解
    好难啊,会也不会设\(a_i=x,a_{i+1}=y\),那么交换后\(a_i=y+1,a_{i+1}=x-1\),发现交换后就是\(a_i+i\)和\(a_{i+1}+i+1\)这两个值进行了交换。那就把所有\(a_i\)变成......
  • 青龙面板调试运行代码时打印语句可能不执行的问题解决
    记录一次用青龙面板调试调用chatGPT的API时发现的一个问题:脚本在调试运行时,有可能会不显示部分打印语句的,例如node.js(python也有这种情况),如下图:关于为什么会出现此问题......
  • lg9018题解
    #include<bits/stdc++.h>usingnamespacestd;#defineN2000010#defineintlonglong#definemo1000000007intjc[N],ij[N],n,a[N];intc(inty,intx){ if(y<x)......