Codeforces Round 890 (Div. 2) E2. PermuTree (hard version) (主席树/树状数组/差分+前缀和)

news2024/12/25 2:39:22

题目

有一个初始为空的数组,你需要处理q(q<=1e6)次操作,操作分四种:

① + x,数组后面加一个新的数x

② - k,删掉数组最后面的k个值

③ !,回滚最后一次变更(只有①操作和②操作视为变更)

④?,询问当前数组内的不同的数的个数(即数的种类数)

E1允许离线,E2强制在线,需要每次输出答案后刷新缓冲区

思路来源

jjleo代码/jiangly代码/官方题解

心得

这个题赛中一看,这不主席树sb题,结果写了一发喜提MLE

然后以为卡卡空间就卡过去了,结果卡了6个小时空间才卡过去,喜提-200分掉到蓝名成就

画风

3s、256M,可以说是非常极限了(不过还没有加快读)

最后卡过去的提交是,考虑到数字都在[0,2^{25}),所以,

用三个unsigned char和一位的bitset模拟了下int,

大概把空间大概压到了3/4(感觉纯纯脑瘫)

题解

主席树

朴素

1. 加数时,按照询问动态开点,在主席树上建一条链

2. 查询时,就全局查询数的种类数,实际只需要用到根节点

3. 回滚时,维护一个数组记录一下操作的点号的序列,退到前一个

4. 删除时,倍增往上跳k个

主席树需要维护lson、rson、num三个变量,num从0变1表示新增,其余非新增,

每个空间1e6*20大概2e7,三个6e7,倍增也需要开1e6*20=2e7,

这样做空间总共约8e7,而256M空间只能开下约6e7的数组

优化

不需要num这个变量

当主席树上建一条新链的时候,在进入叶子结点前,

先判断一下叶子结点这个方向的点是否存在,

已经存在就说明种类数没有新增,否则是新增了一个值

而询问只需要全局询问根,所以只需要每个节点记录一下答案

从而将1e6*20的空间优化到了1e6

树状数组

待补

差分+前缀和O(n)

待补

代码

主席树优化

#include <bits/stdc++.h>
#define maxn 1000086

using namespace std;

int read(){
    int x = 0, f = 1;char ch = getchar();
    while(ch > '9' || ch < '0'){if(ch == '-') f = -1;ch = getchar();}
    while(ch >= '0' && ch <= '9'){x = x * 10 + ch -'0';ch = getchar();}
    return x * f;
}

struct Node{
	int son[2];
}t[maxn * 21];

#define ls(x) (t[x].son[0])
#define rs(x) (t[x].son[1])

int cnt;

int modify(int x, int l, int r, int pos){
	int tag = 0;
	while(l < r){
		int mid = l + r >> 1;
		if(mid >= pos){
			if(!ls(x)) tag = 1;
			t[++cnt] = t[ls(x)], x = ls(x) = cnt, r = mid;
		}else{
			if(!rs(x)) tag = 1;
			t[++cnt] = t[rs(x)], x = rs(x) = cnt, l = mid + 1;
		} 
	}
	return tag;
}

int q;
int fa[maxn][20];
char s[10];
int tot = 1;
int a[maxn], siz;
int ans[maxn], rt[maxn];

int main(){
	q = read();
	int now = 1;
	while(q--){
		scanf("%s", s);
		if(s[0] == '+'){
			int x;
			x = read();
			int p = ++tot;
			fa[p][0] = now;
			for(int i = 1;i < 20;i++) fa[p][i] = fa[fa[p][i - 1]][i - 1];
			rt[p] = ++cnt;
			t[rt[p]] = t[rt[now]];
			ans[p] = ans[now] + modify(rt[p], 1, 1e6, x);
			now = p;
			a[++siz] = now;
		}else if(s[0] == '-'){
			int k;
			k = read();
			for(int i = 0;i < 20;i++) if(k & (1 << i)) now = fa[now][i];
			a[++siz] = now;
		}else if(s[0] == '!'){
			now = a[--siz];
		}else{
			printf("%d\n", ans[now]), fflush(stdout);
		}
	}
}

主席树朴素(空间卡常)

#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define per(i,a,b) for(int i=(a);i>=(b);--i)
typedef long long ll;
typedef double db;
typedef pair<ll,ll> P;
#define fi first
#define se second
#define pb push_back
#define dbg(x) cerr<<(#x)<<":"<<x<<" ";
#define dbg2(x) cerr<<(#x)<<":"<<x<<endl;
#define SZ(a) (int)(a.size())
#define sci(a) scanf("%d",&(a))
#define pt(a) printf("%d",a);
#define pte(a) printf("%d\n",a)
#define ptlle(a) printf("%lld\n",a)
#define debug(...) fprintf(stderr, __VA_ARGS__)
const int N=1e6+10,M=N*22,INF=0x3f3f3f3f,lb=(1<<8)-1,mx=1<<24;
int q,x,y,cur,par[N][10],up=1000000;
int root[N],pos;
int op[N],c;
char s[5];
bitset<M>most[2];
struct node{
	unsigned char a[3];
	int g(){
		int f=0;
		for(int i=2;i>=0;--i){
			f=(f<<8)|a[i];
		}
		return f;
	}
	void s(int x){
		//assert(x<(1<<20));
		for(int i=0;i<3;++i){
			//printf("x&lb:%d\n",x&lb);
			a[i]=x&lb;
			x>>=8;
		}
	}
}sum[M];
node operator+(node a,node b){
	int v1=a.g(),v2=b.g();
	node c;c.s(v1+v2);
	return c;
}
struct node2{
	unsigned char a[3];
	int g(int p,int id){
		int f=0;
		for(int i=2;i>=0;--i){
			f=(f<<8)|a[i];
		}
		if(most[id].test(p))f|=mx;
		return f;
	}
	void s(int p,int id,int x){
		if(x&mx)most[id].set(p);
		else most[id].reset(p);
		for(int i=0;i<3;++i){
			//printf("x&lb:%d\n",x&lb);
			a[i]=x&lb;
			x>>=8;
		}
	}
}ch[M][2];
int copy(int x){
	pos++;
	//if(pos>=M)while(1);
	ch[pos][0]=ch[x][0];
	if(most[0].test(x))most[0].set(pos);
	ch[pos][1]=ch[x][1];
	if(most[1].test(x))most[1].set(pos);
	sum[pos]=sum[x];
	return pos;
}
void add(int k,int l,int r,int x){
	if (l==r) {if(!sum[k].g())sum[k].s(1);return;}
	int mid=(l+r)/2,y=ch[k][0].g(k,0),z=ch[k][1].g(k,1);
	if (x<=mid){
		y=copy(y);
		ch[k][0].s(k,0,y);
		add(y,l,mid,x);
	}
	else{
		z=copy(z);
		ch[k][1].s(k,1,z);
		add(z,mid+1,r,x);
	}
	sum[k]=sum[y]+sum[z];
}

int ask(int k,int l,int r,int a,int b){
	if (!k) return 0;
	if (a==l&&b==r) return sum[k].g();
	int mid=(l+r)/2;
	if (b<=mid) return ask(ch[k][0].g(k,0),l,mid,a,b);
	else if (a>mid) return ask(ch[k][1].g(k,1),mid+1,r,a,b);
	else return ask(ch[k][0].g(k,0),l,mid,a,mid)+ask(ch[k][1].g(k,1),mid+1,r,mid+1,b);
}

void op1(int x){
	int las=cur;
	cur=++y;
	par[cur][0]=las;
	root[cur]=copy(root[las]);
	rep(i,1,9){
		int z=cur;
		for(int j=1;j<=4;++j){
			z=par[z][i-1];
		}
		par[cur][i]=z;
	}
	add(root[cur],1,up,x);
	op[++c]=las;
}
void op2(int k){
	int las=cur;
	for(int i=k,x=0;i;i>>=2,x++){
		int v=i&3;
		for(int j=1;j<=v;++j){
			cur=par[cur][x];
		}
	}
	//printf("cur:%d\n",cur);
	op[++c]=las;
}
void op3(){
	cur=op[c--];
	//printf("cur:%d\n",cur);
	return;
}
void op4(){
	printf("%d\n",sum[root[cur]].g());
	fflush(stdout);
}
int main(){
	//sum[0].s(125);
	//printf("%d\n",sum[0].g());
	sci(q);
	root[0]=pos=1;
	while(q--){
		scanf("%s",s);
		if(s[0]=='+'){
			sci(x);
			op1(x);
		}
		else if(s[0]=='-'){
			sci(x);
			op2(x);
		}
		else if(s[0]=='!'){
			op3();
		}
		else{
			op4();
		}
	}
	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/905337.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Leetcode刷题之快乐数

题⽬描述&#xff1a; 算法原理: 为了⽅便叙述&#xff0c;将「对于⼀个正整数&#xff0c;每⼀次将该数替换为它每个位置上的数字的平⽅和」这⼀个 操作记为 x 操作&#xff1b; 我们做这道题可以参考环形链表:142. 环形链表 II - 力扣&#xff08;LeetCode&#xff09;…

在线HmacSHA224加密工具--在线获取哈希值又称摘要

具体请前往&#xff1a;在线计算HmacSha224工具

Internet Download Manager2023下载器最新中文版本功能

对于idm相信大家都不陌生&#xff0c;全称是Internet Download Manager。idm是一款非常经典、功能强大的Windows文件多线程下载加速软件&#xff0c;在电脑用户中口碑极好&#xff0c;被称为必装的HTTP下载神器。 1、idm既是下载器&#xff0c;也是加速器&#xff0c;可以提升…

next.js 创建 react ant design ts 项目

环境说明&#xff1a;next.js 官方文档要求node版本在16.8以上。笔者使用的 node版本是16.20.1&#xff0c;不要使用16.13.0&#xff0c;笔者在使用 node16.13.0环境时创建的 react 项目点击事件无效 next.js官网截图 next.js 官网&#xff1a;https://nextjs.org/ react 官网…

个人信息保护影响评估(PIA)怎么做?解发条件、实施步骤、操作指南

个人信息保护一直是人们关注的热点话题&#xff0c;互联网、人工智能、大数据等新兴技术的快速发展极大地增强了入侵个人信息的能力&#xff0c;对个人信息的随意收集、违法获取、过度使用、非法买卖、泄露等问题引起了全球各国的普遍关注。同时随着用户的个人信息保护意识的逐…

Flask模型部署教程?

如何使用Flask框架来部署机器学习模型&#xff1f;Flask是一个轻量级的Python Web框架&#xff0c;它非常适合用于将机器学习模型部署成实际应用。 什么是Flask&#xff1f; Flask是一个Python Web应用框架&#xff0c;它允许轻松地构建Web应用程序。它被广泛用于构建各种Web…

基于Java+SpringBoot+Vue的校企合作项目管理系统【源码+论文+演示视频+包运行成功】

博主介绍&#xff1a;✌擅长Java、微信小程序、Python、Android等&#xff0c;专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;&#x1f3fb; 不然下次找不到哟 Java项目精品实战案…

代码随想录(八):贪心算法

文章目录 455.分发饼干376. 摆动序列53. 最大子数组和122. 买卖股票的最佳时机 II55. 跳跃游戏1005. K 次取反后最大化的数组和134. 加油站860. 柠檬水找零135. 分发糖果406. 根据身高重建队列 455.分发饼干 题目链接 C代码&#xff1a; class Solution { public:int findCo…

在Windows下安装PhantomJS和CasperJS及入门介绍(上)

近在使用Python爬取网页内容时&#xff0c;总是遇到JS临时加载、动态获取网页信息的困难。例如爬取CSDN下载资源评论、搜狐图片中的“原图”等&#xff0c;此时尝试学习Phantomjs和CasperJS来解决这个问题。这第一篇文章当然就是安装过程及入门介绍。 一. 安装Phantomjs 下载地…

SWUST派森练习题:P118. 数组接雨

描述 给定一个整形数组​​arr​​**&#xff0c;已知其中所有的值都是非负的&#xff0c;将这个数组看作一个柱子高度图&#xff0c;计算按此排列的柱子&#xff0c;下雨之后能接多少雨水。​​(​​数组以外的区域高度视为​0)** 数据范围&#xff1a;数组长度​​** 0≤n≤…

wustojc2010两小时学完C语言

#include <stdio.h> int main() {int a,b,c;scanf("%d%d%d",&a,&b,&c);printf("%d",a-b*c);return 0;}

AUTOSAR规范与ECU软件开发(实践篇)4.5在Simulink中导入软件组件描述文件——“自上而下”的工作流程

“自上而下”的工作流程有别于“自下而上”的工作流程,其需要先在AAT(AUTOSAR Authoring Tool)工具(如ISOLAR-A)中完成软件组 件框架设计,并将软件组件arxml描述文件导入Matlab/Simulink完成内部 算法的实现,然后再通过Matlab/Simulink生成符合AUTOSAR规范的代 码及arxm…

js 获取页面的滚动高度

想要获取页面的滚动位置可以通过给window绑定滚动事件来实现。 window.addEventListener(scroll,()>{const n document.documentElement.scrollTopconsole.log(n);}) 通过该方法可以获取页面的当前位置&#xff0c;或者实现其他的效果&#xff0c;例如电梯导航

v-model原理

v-model本质上是一个语法糖&#xff0c;应用在输入框上&#xff0c;就是value属性 和input事件的合写 作用:提供数据的双向绑定—实现子组件 和父组件数据的双向绑定 数据变 视图跟着变 :value视图变 数据跟着变 input <input type"text" v-model"msg"…

漏洞指北-VulFocus靶场专栏-中级01

漏洞指北-VulFocus靶场专栏-中级01 中级001 &#x1f338;dcrcms 文件上传 &#xff08;CNVD-2020-27175)&#x1f338;step1&#xff1a;输入账号 密码burp suite 拦截 修改类型为 jpeg 中级002 &#x1f338;thinkphp3.2.x 代码执行&#x1f338;step1&#xff1a;burpsuite …

[保研/考研机试] KY11 二叉树遍历 清华大学复试上机题 C++实现

题目链接&#xff1a; 二叉树遍历_牛客题霸_牛客网编一个程序&#xff0c;读入用户输入的一串先序遍历字符串&#xff0c;根据此字符串建立一个二叉树&#xff08;以指针方式存储&#xff09;。题目来自【牛客题霸】https://www.nowcoder.com/share/jump/43719512169254700747…

【Android】Mobile-Security-Framework-MobSF Manifest 静态扫描规则

前言 移动安全框架&#xff08;MobSF&#xff09;是一个自动化的一体化移动应用程序&#xff08;Android/iOS/Windows&#xff09;测试、恶意软件分析和安全评估框架&#xff0c;能够执行静态和动态分析。MobSF支持移动应用程序二进制文件&#xff08;APK、XAPK、IPA和APPX&am…

JavaScript:DOM (5) 节点的CRUD - 修改、删除

修改(替换)节点 替换子项 replaceChild()可以将指定元素的某个子节点换成新的节点&#xff0c;语法为指定元素.replaceChild(新节点, 旧节点)。 范例&#xff1a; 原始结构&#xff1a; <ul><li>第一项</li><li>第二项</li><li>第三项&l…

Python编程从入门到实践_8-8 用户的专辑_答案

Python编程从入门到实践_8-8 用户的专辑_答案 我也看了一些其他人的答案&#xff0c;很多的答案存在问题&#xff0c;每次调用函数 make_album() 后生成一个专辑字典会覆盖上次调用函数 make_album() 生成的字典&#xff0c;不符合题意。 我采取的解决方案是添加一个空列表 …

全局异常捕获

一、创建普获异常的类 二、定义异常处理器 定义全局异常处理器非常简单&#xff0c;就是定义一个类&#xff0c;在类上加上一个注解RestControllerAdvice&#xff0c;加上这个注解就代表我们定义了一个全局异常处理器。 在全局异常处理器当中&#xff0c;需要定义一个方法来捕…