首页 > 其他分享 >P6864 [RC-03] 记忆 题解(评分:8.1)(2023.12.13)

P6864 [RC-03] 记忆 题解(评分:8.1)(2023.12.13)

时间:2024-04-17 09:04:54浏览次数:25  
标签:8.1 loc cnt 03 int 题解 ans ask 操作

前言

这下又不是官解了吧?

模拟赛题,在一个月后又出现在了数据结构讲稿上,令人忍俊不禁。

Solution

官方解法是用线段树加矩阵,不过赛时的我显然没这么聪明,是想不到的。

赛时我就只知道先发掘一些答案的性质。

一、一些性质

首先,发现这个撤销操作比较棘手,考虑没有撤销操作的情况下,每一个新的操作对答案的贡献。

发现:对于每次操作二,对答案的贡献绝对只有 \(1\)!

只是在开头结尾各自加上一个括号,从左括号 \(+1\)、右括号 \(-1\) 来看,前缀数组是时刻 \(\ge0\) 的,如果在开头结尾加上一个括号,那前缀数组就只有最后一位为 \(0\),也就是以第一个括号开头只能匹配结尾括号,反之亦然。

类似的,考虑操作一在结尾加上一组括号,增加的贡献一定是以最后括号结尾的,此时

(......)(......)(......)  +  ()

前面有几组括号贡献就是组数 \(+1\),例如上图中尾部加入括号,贡献为 \(4\)。

换句话说,操作二贡献恒为 \(1\),操作一贡献取决于前面连续操作一的次数,贡献为连续次数 \(+1\)。

有一种 OSU! 的美。

二、如何维护

你以为这道题就做完了?撤销操作才是本题的重点!

考虑撤销操作可能会对连续操作一的长度有影响。

比如说:

2 1 1 1 1 2 1 1 1 

撤销掉第二个操作二,会导致其左右两边操作一连起来。

就像打音游,本来某个位置一直断,有一次这里全连了,最后连击数就会变高。

而且还可以撤销撤销操作,就导致已经被撤销的操作二可能会打赢复活赛。

换句话说我们得维护一个关于操作二的链表,能支持随时在某个位置插入,删除和查询前面或者后面的第一个操作二。

但是直接写链表,操作一怎么办?

因为我们还需要能够快速得出两个位置之间的操作一次数,这是一个区间查询,链表上显然行不通。

但是偶然间想到一个复杂度稍逊但是也可以维护链表的东西:平衡树!

这道题的解法就显然了:

用 set 维护操作二的插入和删除,记录下每次操作二的位置之后,便可以用树状数组来查询其间操作一数量。

三、具体影响

末尾加操作二,简单,\(+1\) 即可。

末尾加操作一,用 set 找到上一个还活着的操作二,树状数组求出其间的操作一数量为 \(x\) 贡献为 \(x+1\)。

中间插入或删除操作一:找到左右的操作二,剩下同上。

中间插入或删除操作二,看看这个操作二左右两端各有多长的操作一,简单计算即可。

复杂度显然为 \(O(n\log n)\)。

这显然不是官方解法,而且显然比官方做法简单。

AC 代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
int t[1234657],n,cnt;
void change(int x,int v)
{
	for(;x<=n+10;x+=x&-x) t[x]+=v;
}
int ask(int x)
{
	int ans=0;
	for(;x>0;x-=x&-x) ans+=t[x];
	return ans;
}
set<int> s,fs;
int i,j,op,x;
int ot[666666],ch[666666],lo[666666];
signed main()
{
	cin>>n;
	for(i=1;i<=n;i++)
	ch[i]=i;
	int ans=1,p=1;
	s.insert(0);fs.insert(0);
	s.insert(n+1);fs.insert(-n-1);
	for(i=1;i<=n;i++)
	{
		cin>>op;
		ot[i]=op;
		if(op==1)
		{	
			cnt++;
			lo[i]=cnt;
			change(cnt,1);
			int q=-(*fs.upper_bound(-cnt));
			ans+=ask(cnt)-ask(q)+1;
		}
		if(op==2)
		{
			ans++;
			cnt++;
			lo[i]=cnt;
			s.insert(cnt);fs.insert(-cnt);
		}
		if(op==3)
		{
			cin>>x;
			ch[i]=-ch[x];
			if(ch[i]>0)
			{
				int ty=ot[ch[i]],loc=lo[ch[i]];
				int fr=-(*fs.upper_bound(-loc)),bk=*s.upper_bound(loc);
				if(ty==1)
				{
					change(loc,1);
					ans+=ask(bk-1)-ask(fr)+1;
				}
				if(ty==2)
				{
					s.insert(loc);fs.insert(-loc);
					ans++;
					int c=ask(bk-1)-ask(fr);
					ans-=c*(c+3)/2;
					c=ask(loc-1)-ask(fr);
					ans+=c*(c+3)/2;
					c=ask(bk-1)-ask(loc);
					ans+=c*(c+3)/2;
				}
			}
			else
			{
				int ty=ot[-ch[i]],loc=lo[-ch[i]];
				int fr=-*fs.upper_bound(-loc),bk=*s.upper_bound(loc);
				if(ty==1)
				{
					change(loc,-1);
					ans-=ask(bk-1)-ask(fr)+2;
				}
				if(ty==2)
				{
					ans--;
					s.erase(loc);fs.erase(-loc);
					int c=ask(bk-1)-ask(fr);
					ans+=c*(c+3)/2;
					c=ask(loc-1)-ask(fr);
					ans-=c*(c+3)/2;
					c=ask(bk-1)-ask(loc);
					ans-=c*(c+3)/2;
				}
			}
		}
		cout<<ans<<endl;
	}
	return 0;
}

后记

这题解有一种为了一碗醋包了一盘饺子的美。

什么叫数据结构只会树状数组啊。

The End.

标签:8.1,loc,cnt,03,int,题解,ans,ask,操作
From: https://www.cnblogs.com/FunStrawberry/p/18139698

相关文章

  • P2178 [NOI2015] 品酒大会 题解(评分:8.0)(2024.2.23)
    前言"I'mfree."做法与题解区都不同,虽然麻烦,但是毕竟复杂度是对的,而且想法很自然,还是写一写吧!Solution题意:给定长为\(n\)的字符串\(s\)和长为\(n\)的数组\(A\),对于每个\(r\),求满足\(\text{LCP}(\text{Suffix}(x),\text{Suffix}(y))\ger,x<y\)的数对\((x,y)\)数......
  • [error] Error: Fail to open IDE 问题解决
    在使用HBuilder编译器,控制台报[error]Error:FailtoopenIDE 错误如下所示: 有两个原因所致:  其一:微信小程序AppID错误  解决方案:点击项目目录 manifest.json,打开项目配置,将AppID填到配置界面的微信小程序AppID输入框中,重新运行即可,如下所示: 其二:小程序打......
  • MyBatis-03-environment
    配置<environmentsdefault="default"><environmentid="default"><!--事务类型--><transactionManagertype="JDBC"/><!--数据源类型--><dataSourcetype="POOLED">&l......
  • 【爆款推荐】初中中考阅读理解难题一网打尽!句子结构深度解析+答案揭秘,助你轻松冲刺高
    PDF格式公众号回复关键字:ZKYDT003原文1HowmanychildrendoesSumnerhave?解析Howmanychildren多少孩子,SumnerhaveSumner有,标题问Sumner有几个孩子?文本信息IstoppedbecauseIhadneverseen'ournormal'insuchaplace,"themotherofthreechildr......
  • Parcharm-ModuleNotFoundError: No module named 'request'--解决方案
    问题:在Pycharm中报requestsmodule找不到特别的地方:已经通过“pip3installrequests”的命令安装过requests这个模块,并能顺利运行,但是不能在Pycharm中运行 解决方案如下:1.找到Pycharm中的setting设置,并打开2.找到自己工作的目录下的“PythonInterpreter”-->"+......
  • 【题解】P4307 [JSOI2009] 球队收益 / 球队预算
    P4307[JSOI2009]球队收益/球队预算题解题目传送门题意简述一共有\(n\)个球队比赛,输了赢了都会有相应的支出,现在让你安排\(m\)场比赛的输赢,是总支出最少。思路首先看到最小支出,状态不好定义,直接费用流,启动!。后文如果没有特殊说明,边的费用均为\(0\)。考虑建图,其......
  • ABC263Ex Intersection 2 题解
    ABC263ExProblem给定\(N\)条不平行的直线\(A_ix+B_iy+C=0\),\(N\)条直线总共会有\(\frac{N(N-1)}{2}\)个交点(包含在同一个位置的点,即相同位置算不同的点),找出距离原点第\(K\)近的交点的距离。$2\leN\le5\times10^4$,\(1\leK\le\frac{N(N-1)}{2}\),$-1000\le|A_i|,|B_......
  • 洛谷题单指南-数学基础问题-P1403 [AHOI2005] 约数研究
    原题链接:https://www.luogu.com.cn/problem/P1403题意解读:计算1~n每个数的约数个数之和。解题思路:1、数学方法1~n的约数范围也在1~n,要计算每个数的约数个数之和可以从约数出发,比如约数是x,那么在1~n中一共有n/x个数包含x这个约数x从1一直枚举到n,就可以得出每个约数是多少个......
  • CF154C Double Profiles 题解
    CF154CDoubleProfiles题解思路解析题目说的很明白,求有多少个无序点对\((i,j)\),使得与\(i\)直接相连的点集与直接与\(j\)相连的点集完全相等。我们想到如果直接判断每个\(i,j\)肯定会超时,所以我们想把每一个与任意一点直接相连的点集进行压缩,可以想到使用字符串哈希的......
  • [题解] [CCPC陕西省赛2022 D题] Hash
    [CCPC陕西省赛2022D题]Hash题目描述给定一个字符串\(S\),按照如下方法获取\(S\)的哈希值://LanguageC++14longlongmod=5999993;longlonggethas(strings){longlongret=0;for(charc:s)ret=(ret*29+(c-'a'+1))%mod;returnret;}找到一个......