首页 > 其他分享 >Luogu3792 由乃与大母神原型和偶像崇拜 - 线段树 - set -

Luogu3792 由乃与大母神原型和偶像崇拜 - 线段树 - set -

时间:2023-06-16 21:44:45浏览次数:52  
标签:pr set int ny maxn Luogu3792 大母 id

题目链接:https://www.luogu.com.cn/problem/P3792

题解:
一点小小的空间震撼(ML:125MB)
image

首先询问可以转化成:区间 \([l,r]\) 的 \(max-min+1=r-l+1\) 并且区间内没有重复元素。可以考虑对每个点 \(i\) 记一个前驱结点 \(pr_i\),表示 \(a_{pr_i}=a_i\),且 \(pr_i\) 是 \(i\) 前面离 \(i\) 最近的点
这样没有重复元素这个条件就变成了区间 \([l,r]\) 中最大的 \(pr<l\)。

如何维护 \(pr_i\) 呢?想到可以用 set,可以将原数组+修改的数离散化之后,用 set 存对应数字的位置都有哪些。每次修改的时候就修改原来 \(i\) 对应后继的 \(pr\),现在 \(i\) 的 \(pr\),现在 \(i\) 的后继的 \(pr\)。这个部分利用 set 的 \(find()\) 和 迭代器的加减可以很容易的实现。

\(pr\) 的区间最大值、单点修改可以用线段树实现。

直接这么做的话会 MLE,考虑优化。
我们发现,实际上需要离散化的部分只有记录每种数字对应的位置都有哪些的那个 set 数组,可以考虑先把 \(a[]\) 数组离散化之后,对于每个修改,如果修改之后有一种数字没有在数组中出现过了,我们可以将这个下标回收,对于下一个需要离散化开的下标,可以从回收中的下标中先取,这样就能节省空间了。

// by SkyRainWind
#include <bits/stdc++.h>
#define mpr make_pair
#define debug() cerr<<"Yoshino\n"
#define pii pair<int,int>
#define pb push_back

using namespace std;

typedef long long ll;
typedef long long LL;

const int inf = 1e9, INF = 0x3f3f3f3f, maxn = 5e5 + 5, maxm = 1e6+5;

int n,qu;
int ls[maxn], cnt = 0;
int pre[maxn], prei[maxn], a[maxn], b[maxn];
// a[] 存离散化后的数,b[] 存未离散化时的数(每次修改都更新) 
set<int>id[700005];	// id[j] 代表离散化之后的 j 这个数对应的数组中的位置,为了方便每个用到的 j 前面都加了个 0 
map<int,int>ifocc;	// ifocc[i] 离散化过后为 i 的下标是否回收,如果否,这个下标对应的原数是什么 
int stk[maxn], tp=0;	// 记录哪些下标回收了 

struct segm{
	int mn, mx, pr;
}se[maxn << 2];

void pushup(int num){
	se[num].mn = min(se[num << 1].mn, se[num << 1|1].mn);
	se[num].mx = max(se[num << 1].mx, se[num << 1|1].mx);
	se[num].pr = max(se[num << 1].pr, se[num << 1|1].pr);
}

void build(int x,int y,int num){
	if(x == y){
		se[num].mn = se[num].mx = b[x];
		se[num].pr = prei[x];
		return ;
	}
	
	int mid = x+y>>1;
	build(x,mid,num << 1);build(mid+1,y,num << 1|1);
	pushup(num);
}

void update(int suf,int pre,int to,int l,int r,int num){
	if(l == r){
		se[num].pr = pre;
		se[num].mx = se[num].mn = to;
		return ; 
	}
	int mid = l+r>>1;
	if(suf <= mid)update(suf,pre,to,l,mid,num << 1);
	else update(suf,pre,to,mid+1,r,num << 1|1);
	pushup(num);
}

segm query(int x,int y,int l,int r,int num){
	if(x <= l && r <= y)
		return se[num];
	int mid = l+r>>1;
	if(y <= mid)return query(x,y,l,mid,num << 1);
	else if(x > mid)return query(x,y,mid+1,r,num << 1|1);
	else{
		segm s1 = query(x,y,l,mid,num << 1);
		segm s2 = query(x,y,mid+1,r,num << 1|1);
		return segm{min(s1.mn,s2.mn), max(s1.mx,s2.mx), max(s1.pr,s2.pr)};
	}
}

signed main(){
	scanf("%d%d",&n,&qu);
	for(int i=1;i<=n;i++)scanf("%d",&a[i]), ls[++ cnt] = b[i] = a[i];

	sort(ls+1,ls+cnt+1);
	cnt = unique(ls+1,ls+cnt+1) - (ls + 1);
	for(int i=1;i<=n;i++)
		a[i] = lower_bound(ls+1,ls+cnt+1,a[i]) - ls,
		id[a[i]].insert(i),
		ifocc[b[i]] = a[i];
		
	for(int i=1;i<=cnt;i++)
		id[i].insert(0);
	
	for(int i=1;i<=n;i++){
		prei[i] = pre[a[i]];
		pre[a[i]] = i;
	}
	build(1,n,1);
	
	for(int i=1;i<=qu;i++){
		int op,x,y;
		scanf("%d%d%d",&op,&x,&y);
		// y -> ny
		
		if(op == 1){
			int ny;
			if(ifocc.count(y))
				ny = ifocc[y];
			else{
				if(tp){
					ny = stk[tp --];
				}else ny = ++ cnt, id[cnt].insert(0);
				ifocc[y] = ny;
			}

			int nowc = a[x];
			int j = x;
			set<int>::iterator it = id[nowc].find(j);
			
			int prev = 0, suff;
			
			prev = *(--it);
			++ it;
			++ it;
			if(it != id[nowc].end()){
				suff = *it;
				update(suff,prev,b[suff],1,n,1);
					// 原来 i 对应的数的后面一个结点的 pr 需要修改 
			}
			-- it;
			id[nowc].erase(it);
			if(id[nowc].size() == 1)
				stk[++ tp] = nowc,
				ifocc.erase(ls[a[x]]);
			
			int toc = ny;
			id[toc].insert(j);
			it = id[toc].find(j);
			
			prev = *(-- it);
			++ it;
			update(j,prev,y,1,n,1);
			++ it;
			// i 修改过后 i 的 pr 以及 i 的后继的 pr 都需要修改 
			if(it != id[toc].end()){
				suff = *it;
				update(suff,j,y,1,n,1);
			}
			-- it;
			a[j] = toc;
			b[j] = y;
		}else{
			int l = x, r = y;
			segm res = query(l,r,1,n,1);
			if(res.mx - res.mn == r-l && res.pr < l)
				puts("damushen");
			else
				puts("yuanxing");
		}
	}

	return 0;
}

标签:pr,set,int,ny,maxn,Luogu3792,大母,id
From: https://www.cnblogs.com/SkyRainWind/p/17486558.html

相关文章

  • ABP框架中UnitOfWorkManager.Current.SetTenantId()并不是修改AbpSession.TenantId的
    1.结论UnitOfWorkManager.Current.SetTenantId()修改的是ABP过滤器中使用的TenantId,并不会修改AbpSession.TenantId代码演示:2.关于UnitOfWorkManager.Current.SetTenantId()方法的作用前提:ABP框架是是支持多租户的,对于单数据库的多租户设计,需要通过TenantId来区分宿主和......
  • Python中常用set()方法详解!
    set是Python中一种集合数据类型,表示一个无序且不重复的集合。set()方法可以用于创建一个空的集合,也可以将其他可迭代对象转换为集合。与其他Python数据类型不同,set没有索引,不能通过索引访问其元素,但可以使用一些方法来操作和访问集合中的元素。1、add():添加一个元素到set集......
  • HashSet、LInkedHashSet的使用和特点
    HashSet的使用Java中的HashSet是CollectionsFramework中的一个类。它允许您使用哈希表在集合中存储多个值。哈希表借助哈希机制以无序的方式存储值。导入java.util.HashSet包后,以下是在Java中创建HashSet的语法:HashSet<data_type>name=newHashSet(capacity,lo......
  • k8s实战案例之基于StatefulSet控制器运行MySQL一主多从
    1、前言Pod调度运⾏时,如果应⽤不需要任何稳定的标示、有序的部署、删除和扩展,则应该使⽤⼀组⽆状态副本的控制器来部署应⽤,例如Deployment或ReplicaSet更适合⽆状态服务需求,⽽StatefulSet适合管理所有有状态的服务,⽐如MySQL、MongoDB集群等。2、StatefulSet控制器运行MySQL一......
  • redis学习八:数据类型命令及落地运用 (Zset)
    有序,附带分数,适用于排行榜1.zaddkeyscore1v1score2v2新增键值对;zrangezsetstartend查看对应范围值zrangekeystartendwithscores带着分数查看;zrevrangekey倒序查看,用法和zrange类似; 2.zrangebyscorekeyminmax取分数范围内的value;也可以在前面加上(是不......
  • 关于vue 使用setInterval定时器关闭失效的问题 原因为事件传播
    /****data.isPlay为显示那个按钮**startHandle开始定时器setInterval**pauseHandle,stopHandle理解为关闭定时器就好了clearInterval**/<viewclass="btn"@click.stop="startHandle"><viewclass="btn-statusbtn-play"><view......
  • git push -u origin master 与git push --set-upstream origin master
    在github上新建仓库时提示push代码的指令:gitinitgitaddREADME.mdgitcommit-m"firstcommit"gitbranch-Mmaingitremoteaddoriginhttps://github.com/helloyzp/AlgorithmProject.gitgitpush-uoriginmain以前的提示一直是gitpush--set-upstreamoriginm......
  • 简单:SuperSet
    项目简介本文是关于安装和配置直接从数据库中直接呈现的超酷和令人钦佩的D3图表,而无需任何特殊的API。这些工具名为  SuperSet,它来自Airbnb的团队。本文分为两部分。一个解释了Docker的安装方法,另一个解释了使用Python在本地机器上安装SuperSet。以下是两个部分需要完成的常见操......
  • JDBC-API详解-ResultSet2
     packageTest;importorg.junit.Test;importjava.sql.Connection;importjava.sql.DriverManager;importjava.sql.ResultSet;importjava.sql.Statement;importjava.util.ArrayList;importjava.util.List;importjava.util.TimerTask;publicclassJDBCdem......
  • 使用sessionStorage获取值和设置值 sessionStorage.setItem('key','value') sessionS
    使用sessionStorage获取值和设置值sessionStorage.setItem('key','value')sessionStorage.getItem('myname')https://www.shuzhiduo.com/A/lk5a4ZL2J1/<body><buttonid="btn1">设置值</button><buttonid="btn2&......