IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> [NOI2003]文本编辑器 -> 正文阅读

[数据结构与算法][NOI2003]文本编辑器

文本编辑器

恶心人的大模拟(?or 平衡树),发现我两年前就一直卡着没过,今天写过了发一发题解

我们明显维护一个可以动态插入删除字符,并查询一段区间字符的数据结构,这不就是平衡树吗。
所以打FHQ_Treap! 既然教练叫用 S p l a y Splay Splay做,那就用 S p l a y Splay Splay吧。还是别用 S p a l y Spaly Spaly

对于光标位置的操作 1 , 5 , 6 1,5,6 1,5,6,我们只需要单独记录一个指针维护光标的位置。
而关于字符串的操作 2 , 3 , 4 2,3,4 2,3,4设计到区间插入,删除之类的操作,显然我们需要将一棵 S p l a y Splay Splay按大小分为两段的操作与将两棵 S p l a y Splay Splay合并在一起的操作。
显然,分成两段我们只需要将要分割的那个点旋到根,再将根与它的儿子分裂成两棵 S p l a y Splay Splay
而合并,我们只需要将一棵树的最左端点旋到根,这样根就没左儿子了,将另一棵 S p l a y Splay Splay接在上面即可。
简单易懂的操作,之后就跟 F H Q _ T r e a p FHQ\_Treap FHQ_Treap的操作一样了 ,这大家都会吧,也没什么好解释的,就是先把要操作的区间分出来,处理后再合并回去而已

时间复杂度 O ( n log ? ? n + M ) O\left(n\log\,n+M\right) O(nlogn+M) M M M是总字符数。
注意,输入数据中不在ASCII [ 32 , 126 ] [32,126] [32,126]之内的字符是不能出现在文本中的,输入中出现了就删掉。

源码

#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN ((1<<21)+5)
#define lowbit(x) (x&-x)
#define reg register
#define pb push_back
#define mkpr make_pair
#define fir first
#define sec second
typedef long long LL;
typedef unsigned long long uLL;
const int INF=0x3f3f3f3f;
const int mo=1e9+7;
const int inv2=499122177;
const int jzm=2333;
const int zero=10000;
const int orG=3,invG=332748118;
const double Pi=acos(-1.0);
const double eps=1e-5;
typedef pair<int,int> pii;
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
	_T f=1;x=0;char s=getchar();
	while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
	while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
	x*=f;
}
template<typename _T>
void print(_T x){if(x<0){x=(~x)+1;putchar('-');}if(x>9)print(x/10);putchar(x%10+'0');}
LL gcd(LL a,LL b){return !b?a:gcd(b,a%b);}
int add(int x,int y,int p){return x+y<p?x+y:x+y-p;}
void Add(int &x,int y,int p){x=add(x,y,p);}
int qkpow(int a,int s,int p){int t=1;while(s){if(s&1LL)t=1ll*a*t%p;a=1ll*a*a%p;s>>=1LL;}return t;}
int n,stak;char str[MAXN];
struct ming{
	int ch[2],fa,siz;char val;
	ming(){ch[0]=ch[1]=fa=val=siz=0;}
}; 
class Splay{
	#define root tr[0].ch[1]
	private:
		ming tr[MAXN];int tot;
		void pushup(int rt){tr[rt].siz=tr[tr[rt].ch[0]].siz+tr[tr[rt].ch[1]].siz+1;}
		int identify(int rt){return tr[tr[rt].fa].ch[0]!=rt;}
		void link(int rt,int f,int d){tr[rt].fa=f;tr[f].ch[d]=rt;}
		void rotate(int x){
			int y=tr[x].fa,z=tr[y].fa,d1=identify(y),d2=identify(x),B=tr[x].ch[d2^1];
			link(B,y,d2);link(y,x,d2^1);link(x,z,d1);pushup(y);pushup(x);
		}
		void splay(int x,int y){
			y=tr[y].fa;
			while(tr[x].fa!=y){
				int z=tr[x].fa;
				if(tr[z].fa==y)rotate(x);
				else if(identify(z)==identify(x))rotate(z),rotate(x);
				else rotate(x),rotate(x);
			}
			if(!y)root=x;
		}
		int newnode(char w){int rt=++tot;tr[rt].val=w;tr[rt].siz=1;return rt;}
		int getRoot(){return root;}
		int build(int l,int r){
			int mid=l+r>>1,rt=newnode(str[mid]);
			if(l<mid)link(build(l,mid-1),rt,0);
			if(r>mid)link(build(mid+1,r),rt,1);
			pushup(rt);
			return rt;
		}
		int findNum(int &rt,int k){
			int now=rt;
			while(k){
				if(k==tr[tr[now].ch[0]].siz+1)break;
				if(k<=tr[tr[now].ch[0]].siz)now=tr[now].ch[0];
				else k-=tr[tr[now].ch[0]].siz+1,now=tr[now].ch[1];
			}
			splay(now,rt);rt=now;return now;
		}
		void split(int now,int k,int &x,int &y){
			if(!now){x=y=0;return ;}
			if(!k){x=0;y=now;return ;}
			x=findNum(now,k),y=tr[x].ch[1];
			tr[x].ch[1]=tr[y].fa=0;pushup(x);
		}
		int merge(int x,int y){
			if(!x||!y)return x+y;
			int z=findNum(y,1);link(x,z,0);pushup(z);
			return z;
		}
		void Print(int rt){
			if(tr[rt].ch[0])Print(tr[rt].ch[0]);
			putchar(tr[rt].val);
			if(tr[rt].ch[1])Print(tr[rt].ch[1]);
		}
	public:
		void Insert(int x){
			int x1,y1;split(root,x,x1,y1);
			link(merge(x1,merge(build(1,stak),y1)),0,1);
		}
		void Remove(int x,int y){
			int x1,y1,x2,y2;split(root,y,x1,y1);
			split(x1,x-1,x2,y2);link(merge(x2,y1),0,1);
		}
		void Get(int x,int y){
			int x1,y1,x2,y2;split(root,y,x1,y1);
			split(x1,x-1,x2,y2);Print(y2);puts("");
			link(merge(merge(x2,y2),y1),0,1);
		}
	#undef root
}T;
int now;
signed main(){
	read(n);now=0;int tot=0;
	for(int i=1;i<=n;i++){
		char opt[10]={};scanf("\n%s",opt+1);
		if(opt[1]=='M'){int k;read(k);now=k;}
		if(opt[1]=='I'){
			read(stak);
			for(int i=1;i<=stak;i++){
				str[i]=getchar();
				if(str[i]=='\n'||str[i]=='\r')i--;	
			}
			T.Insert(now);tot+=stak;
		}
		if(opt[1]=='D'){int len;read(len);T.Remove(now+1,now+len);tot-=len;}
		if(opt[1]=='G'){int len;read(len);T.Get(now+1,now+len);}
		if(opt[1]=='P')now=max(now-1,0);
		if(opt[1]=='N')now=min(now+1,tot);
	}
	return 0;
}

谢谢!!!

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-09-04 17:47:48  更:2021-09-04 17:49:33 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 1:48:38-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码