数颜色 (洛谷)(可持久化线段树(x))

本文介绍了如何在权值线段树中进行元素交换操作,并详细讲解了更新rt数组及子节点的过程。通过示例代码展示了针对2操作的处理,涉及构建、更新和查询操作。同时,提及了使用vector进行辅助存储和二分查找的解决方案。
摘要由CSDN通过智能技术生成

题目地址
配套地址
在这里插入图片描述

被卡掉了。权值线段树维护,对于2操作,起始就是交换元素后,更新rt[x]和rt[x+1]

主席树

#include<bits/stdc++.h>
using namespace std;
const int N = 3e5 + 10,M = 1e6 + 10;

int rt[N],len[N];
int a[N];

#define ls(x) t[x].ls
#define rs(x) t[x].rs
#define sum(x) t[x].sum

struct LSegmentTree{
	int ls,rs,sum;
}t[M<<5];
int idx = 0;

int build(int l,int r){
	int root = ++idx;
	sum(root) = 0;
	if(l == r) return root;
	int mid = (l + r) >> 1;
	ls(root) = build(l,mid);
	rs(root) = build(mid+1,r);
	return root;
}

int update(int p,int l,int r,int pos){
	int root = ++idx;
	ls(root) = ls(p),rs(root) = rs(p),sum(root) = sum(p) + 1;
	if(l == r) return root;
	int mid = (l + r) >> 1;
	if(pos <= mid) ls(root) = update(ls(p),l,mid,pos);
	else rs(root) = update(rs(p),mid+1,r,pos);
	return root;
}

int query(int lp,int rp,int l,int r,int pos){
	if(l == r) return sum(rp) - sum(lp);
	int mid = (l + r) >> 1;
	if(pos <= mid) return query(ls(lp),ls(rp),l,mid,pos);
	else return query(rs(lp),rs(rp),mid+1,r,pos);
}

signed main(){
    rt[0] = build(1,N);
    int n,m; scanf("%d %d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d",a+i),rt[i] = update(rt[i-1],1,N,a[i]);
    for(int i=1;i<=m;i++){
    	int op; scanf("%d",&op);
    	if(op == 1){
    		int l,r,c; scanf("%d %d %d",&l,&r,&c);
    		printf("%d\n",query(rt[l-1],rt[r],1,N,c));
		}else{
			int x; scanf("%d",&x);
			swap(a[x],a[x+1]);
			rt[x] = update(rt[x-1],1,N,a[x]);
			rt[x+1] = update(rt[x],1,N,a[x+1]);
		}
	}
    
	return 0;
}

vector存每个位置,然后二分。

#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#include<bits/stdc++.h>
using namespace std;
const int N = 3e5 + 10;

int a[N];
vector<int> ve[N];

signed main(){
	IOS
    int n,m; cin>>n>>m;
    for(int i=1;i<=n;i++) cin>>a[i],ve[a[i]].push_back(i);
    while(m --){
    	int op; cin>>op;
    	if(op == 1) {
    		int l,r,c; cin>>l>>r>>c;
    		if(ve[c].size() == 0){
    			cout<<0<<endl;
    			continue;
			}
    		l = lower_bound(ve[c].begin(),ve[c].end(),l) - ve[c].begin();
    		r = upper_bound(ve[c].begin(),ve[c].end(),r) - ve[c].begin();
    		int ans = r - l;
    		cout<<ans<<endl;
		}else{
			int x; cin>>x;
			int k1 = a[x],k2 = a[x+1];
			swap(a[x],a[x + 1]);
			*lower_bound(ve[k1].begin(),ve[k1].end(),x) = x + 1;
			*lower_bound(ve[k2].begin(),ve[k2].end(),x + 1) = x;
		}
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值