首页 > 其他分享 >P3285 [SCOI2014]方伯伯的OJ

P3285 [SCOI2014]方伯伯的OJ

时间:2022-09-28 12:13:01浏览次数:75  
标签:map OJ int P3285 tr son fa SCOI2014 id

P3285 SCOI2014方伯伯的OJ

Splay + 将一个区间合并为一个点,类似P3960NOIP07列队
用STL的map存被合并区间的右端点对应的节点下标,查询节点下标时lower_bound即可

点击查看代码

#include <map>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

constexpr int N = 5e6 + 5;
int n, q;
std::map<int, int> map;

struct Node {
	int son[2], fa;
	int l, r; // 这段区间存的是编号[l,r]的节点
	int size;
} tr[N];
int root, idx;

inline void push_up(int u) {
	tr[u].size = tr[tr[u].son[0]].size + tr[tr[u].son[1]].size + (tr[u].r - tr[u].l + 1);
}
void rotate(int x) {
	int y = tr[x].fa, z = tr[y].fa, k = tr[y].son[1] == x;
	tr[tr[z].son[tr[z].son[1] == y] = x].fa = z;
	tr[tr[y].son[k] = tr[x].son[!k]].fa = y;
	tr[tr[x].son[!k] = y].fa = x;
	push_up(y), push_up(x);
}
void splay(int x, int rt) {
	while(tr[x].fa != rt) {
		int y = tr[x].fa, z = tr[y].fa;
		if(z != rt) rotate((tr[y].son[1] == x) ^ (tr[z].son[1] == y) ? x : y);
		rotate(x);
	}
	if(!rt) root = x;
}
// 将节点u分裂:u保留<=k的,返回一个新的节点(后若干)
int split(int u, int k) {
	int v = ++ idx;
	tr[v].l = k + 1, tr[v].r = tr[u].r;
	tr[u].r = k;
	if(tr[u].son[1]) {
		int t = tr[u].son[1];
		while(tr[t].son[0]) t = tr[t].son[0];
		tr[tr[t].son[0] = v].fa = t;
	} else tr[tr[u].son[1] = v].fa = u;
	splay(v, 0);
	return v;
}
// 将编号为id的节点拉出来,返回其编号,更新其余块(不更新自己)
int split3(int id) {
	std::map<int, int>::iterator it = map.lower_bound(id);
	if(it == map.end()) exit(0x7fffffff);
	int u = it->second; // 得到id所在块
	if(id < tr[u].r) it->second = split(u, id); // 右边分裂
	else map.erase(it); // 没有右边了:暂时删除
	if(id > tr[u].l) map[id - 1] = u, u = split(u, id - 1); // 左边分裂,左边单独为一块
	return u;
}
// 得到排名
int getrnk(int u) {
	splay(u, 0); // 旋转到根,左子树大小
	return tr[tr[u].son[0]].size + 1;
}
// 重命名id为newid
int rename(int id, int newid) {
	int u = split3(id); // 找到这个节点
	map[tr[u].l = tr[u].r = newid] = u; // 更新id
	return getrnk(u);
}
// “暂时”删除
void remove_temp(int u) {
	splay(u, 0);
	tr[tr[u].son[0]].fa = tr[tr[u].son[1]].fa = 0;
	if(tr[u].son[0]) {
		int t = tr[u].son[0];
		while(tr[t].son[1]) t = tr[t].son[1];
		splay(t, 0);
		tr[tr[t].son[1] = tr[u].son[1]].fa = t;
		push_up(t);
	} else root = tr[u].son[1];
}
// 移到最前面
int move_to_front(int id) {
	int u = split3(id); // 找到这个节点
	map[tr[u].l] = u; // 此时必有tr[u].l=tr[u].r;更新id
	int ret = getrnk(u);
	remove_temp(u);
	tr[u].son[0] = tr[u].son[1] = tr[u].fa = 0;
	int v = root;
	while(tr[v].son[0]) v = tr[v].son[0];
	tr[tr[v].son[0] = u].fa = v;
	splay(u, 0);
	return ret;
}
// 移到最后面
int move_to_back(int id) {
	int u = split3(id);
	map[tr[u].l] = u;
	int ret = getrnk(u);
	remove_temp(u);
	tr[u].son[0] = tr[u].son[1] = tr[u].fa = 0;
	int v = root;
	while(tr[v].son[1]) v = tr[v].son[1];
	tr[tr[v].son[1] = u].fa = v;
	splay(u, 0);
	return ret;
}
// 根据排名得到编号
int getid(int k) {
	int u = root, lssz;
	while(u) {
		lssz = tr[tr[u].son[0]].size;
		if(lssz >= k) u = tr[u].son[0];
		else if(lssz + (tr[u].r - tr[u].l + 1) >= k) return tr[u].l + (k - lssz) - 1;
		else k -= lssz + (tr[u].r - tr[u].l + 1), u = tr[u].son[1];
	}
	return 0; // 不存在
}
// 初始化
void init() {
	root = ++ idx;
	tr[idx].l = 1, tr[idx].r = n, tr[idx].size = n;
	map[n] = idx;
}

int main() {
	scanf("%d%d", &n, &q), init();
	for(int i = 1, op, x, y, a = 0; i <= q; i ++) {
		scanf("%d%d", &op, &x);
		if(op == 1) scanf("%d", &y), a = rename(x - a, y - a);
		else if(op == 2) a = move_to_front(x - a);
		else if(op == 3) a = move_to_back(x - a);
		else a = getid(x - a);
		printf("%d\n", a);
	}
	return 0;
}

标签:map,OJ,int,P3285,tr,son,fa,SCOI2014,id
From: https://www.cnblogs.com/azzc/p/16737554.html

相关文章

  • [BZOJ3694. 最短路]
    BZOJ3694.最短路并查集:按权值排序,暴力更新;每次记录一个祖先:从没有被更新的开始更新点击查看代码</details>#include<stdio.h>#include<string.h>#include......
  • VS2010创建windows服务其实很简单 ProjectInstaller.cs Timer
    VS2010创建windows服务其实很简单ProjectInstaller.cs【IT168技术】很多人会对使用VisualStudio有不少的烦恼,下面我们来看一下作者是如何创建windows服务的,看后你......
  • TZOJ 7509求1e8以内的素数个数 埃氏筛/欧拉筛
    描述  给定一个正整数N,求出1到N中有多少个素数。  输入  输入一行一个正整数N。对于30%的数据,N<=100对于70%的数据,N<=5000对于100%的数据,N<=10000......
  • mybatisPlus逆向生成工具类CodeGenerator (生成pojo、controller、service等)
    importcom.baomidou.mybatisplus.annotation.IdType;importcom.baomidou.mybatisplus.generator.AutoGenerator;importcom.baomidou.mybatisplus.generator.config.Da......
  • Project related English
    Projectmanagement:Yourgoodsentences:-Thedevelopmentteamshouldtakeresponsibility.-Theproductionteamshouldtakemoreresponsibility.-Weneedtoin......
  • Vue中使用introjs插件实现页面引导效果及设置Options(设置中文显示)示例
    场景若依前后端分离版手把手教你本地搭建环境并运行项目:https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/108465662在上面的基础上,实现页面引导/新手指引的......
  • [loj6079]养猫
    以下线性规划问题,可以转化为费用流:有$m$个变量,有限制$x_{i}\in[0,r_{i}]\capN$有$n$个等式,每个等式形如$\sum_{i\inU_{j}}x_{i}-\sum_{i\inV_{j}}x_{i}=C_{j}$目标......
  • 应用Lombok 插件--提高使用 POJO 类的效率
    不评价使用Lombok的好坏什么是Lombok?lombok⼀个优秀的Java代码库,简化了Java的编码,为Java代码的精简提供了⼀种⽅式可以自动生成JavaBean的getter,setter,equal......
  • SOJ1626 方珍 题解
    传送门题意给定一个\(n×n\)的方阵,其中第\(i\)行为\(A_{i,1},A_{i,2},...,A_{i,n}\)。对于\(A_i\)的所有区间,设\(f_i\)为其中第\(k_i\)大的\(mex\)值。给......
  • Solution - 「OurOJ #47407」巧立名目
    \(\mathscr{Description}\)  Privatelink.  给定一棵含有\(n\)个点的带点权树和大小为\(m\)的有序点对集合\(\{(s_i,t_i)\}_{i=1}^n\).每次操作可以选择一个......