返回顶部
大江东去,浪淘尽,千古风流人物。故垒西边,人道是,三国周郎赤壁。乱石穿空,惊涛拍岸,卷起千堆雪。江山如画,一时多少豪杰。遥想公瑾当年,小乔初嫁了,雄姿英发。羽扇纶巾,谈笑间,樯橹灰飞烟灭。故国神游,多情应笑我,早生华发。人生如梦,一尊还酹江月。

splay(水题)

昨天讲了splay,然而一脸蒙蔽,今天写了个模版

洛谷p3369

没错,标准模版

题目描述

您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:

  1. 插入xxx数
  2. 删除xxx数(若有多个相同的数,因只删除一个)
  3. 查询xxx数的排名(排名定义为比当前数小的数的个数+1+1+1。若有多个相同的数,因输出最小的排名)
  4. 查询排名为xxx的数
  5. xxx的前驱(前驱定义为小于xxx,且最大的数)
  6. xxx的后继(后继定义为大于xxx,且最小的数)

输入输出格式

输入格式:

第一行为nnn,表示操作的个数,下面nnn行每行有两个数optoptopt和xxx,optoptopt表示操作的序号( 1≤opt≤6 1 \leq opt \leq 6 1opt6 )

输出格式:

对于操作3,4,5,63,4,5,63,4,5,6每行输出一个数,表示对应答案

输入输出样例

输入样例#1: 复制
10
1 106465
4 1
1 317721
1 460929
1 644985
1 84185
1 89851
6 81968
1 492737
5 493598
输出样例#1: 复制
106465
84185
492737

说明

时空限制:1000ms,128M

1.n的数据范围: n≤100000 n \leq 100000 n100000

2.每个数的数据范围: [−107,107][-{10}^7, {10}^7][107,107]

来源:Tyvj1728 原名:普通平衡树

在此鸣谢

 

细节决定一切,模版要慢慢打

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 const int inf=1e7+10;
  4 const int maxn=200005;
  5 int par[maxn],cnt[maxn],ch[maxn][2],size[maxn],val[maxn],ncnt=0,n,root;
  6 void pushup(int x){
  7     size[x]=size[ch[x][0]]+size[ch[x][1]]+cnt[x];
  8 }
  9 bool chk(int x){
 10     return ch[par[x]][1]==x;
 11 }
 12 void rotate(int x){
 13     int y=par[x],z=par[y],k=chk(x),w=ch[x][k^1];
 14     ch[y][k]=w;
 15     par[w]=y;
 16     ch[z][chk(y)]=x;
 17     par[x]=z;
 18     ch[x][k^1]=y;
 19     par[y]=x;
 20     pushup(y);pushup(x);
 21 }
 22 void splay(int x,int goal=0){
 23     while(par[x]!=goal){
 24         int y=par[x],z=par[y];
 25         if(z!=goal){
 26             if(chk(x)==chk(y)) rotate(y);
 27             else rotate(x);
 28         }
 29         rotate(x);
 30     }
 31     if(!goal) root=x;
 32 }
 33 void insert(int x){
 34     int cur=root,fa=0;
 35     while(val[cur]!=x&&cur){
 36         fa=cur;
 37         cur=ch[cur][x>val[cur]];
 38     }
 39     if(cur){
 40         cnt[cur]++;
 41     }
 42     else {
 43         cur=++ncnt;val[cur]=x;
 44         if(fa)
 45         ch[fa][x>val[fa]]=cur;
 46         ch[cur][0]=ch[cur][1]=0;
 47         size[cur]=1;cnt[cur]=1;
 48         par[cur]=fa;
 49     }
 50     splay(cur);
 51 }
 52 void find(int x){
 53     int cur=root;
 54     while(val[cur]!=x&&ch[cur][x>val[cur]]) cur=ch[cur][x>val[cur]];
 55     splay(cur);
 56 }
 57 int kth(int k){
 58     int cur=root;
 59     while(1){
 60         if(size[ch[cur][0]]>=k) cur=ch[cur][0];
 61         else if(size[ch[cur][0]]+cnt[cur]>=k) return cur;
 62         else {
 63             k-=size[ch[cur][0]]+cnt[cur];
 64             cur=ch[cur][1];
 65         }
 66     }
 67 }
 68 int pre(int x){
 69     find(x);
 70     int cur=root;
 71     if(val[cur]<x) return cur;
 72     cur=ch[cur][0];
 73     while(ch[cur][1]) cur=ch[cur][1];
 74     return cur;
 75 }
 76 int suc(int x){
 77     find(x);
 78     int cur=root;
 79     if(val[cur]>x) return cur;
 80     cur=ch[cur][1];
 81     while(ch[cur][0]) cur=ch[cur][0];
 82     return cur;
 83 }
 84 void remove(int x){
 85     int last=pre(x),next=suc(x);
 86     splay(last);
 87     splay(next,last);
 88     if(cnt[ch[next][0]]==1){
 89         ch[next][0]=0;
 90     }
 91     else {
 92         cnt[ch[next][0]]--;
 93         splay(ch[next][0]);
 94     }
 95 }
 96 int main(){
 97     scanf("%d",&n);
 98     insert(inf);insert(-inf);
 99     for(int i=1;i<=n;i++){
100         int opt,x;
101         scanf("%d%d",&opt,&x);
102         switch(opt){
103             case 1:
104                 insert(x);
105                 break;
106             case 2:
107                 remove(x);
108                 break;
109             case 3:
110                 find(x);
111                 printf("%d\n",size[ch[root][0]]);
112                 break;
113             case 4:
114                 printf("%d\n",val[kth(x+1)]);
115                 break;
116             case 5:
117                 printf("%d\n",val[pre(x)]);
118                 break;
119             case 6:
120                 printf("%d\n",val[suc(x)]);
121                 break;
122         }
123     }
124     return 0;
125 }
View Code

还有一道要转化的题

洛谷p1503

鬼子进村

题目背景

小卡正在新家的客厅中看电视。电视里正在播放放了千八百次依旧重播的《亮剑》,剧中李云龙带领的独立团在一个县城遇到了一个鬼子小队,于是独立团与鬼子展开游击战。

题目描述

描述 县城里有n个用地道相连的房子,第i个只与第i-1和第i+1个相连。这是有m个消息依次传来

1、消息为D x:鬼子将x号房子摧毁了,地道被堵上。

2、消息为R :村民们将鬼子上一个摧毁的房子修复了。

3、消息为Q x:有一名士兵被围堵在x号房子中。

李云龙收到信息很紧张,他想知道每一个被围堵的士兵能够到达的房子有几个。

输入输出格式

输入格式:

第一行2个整数n,m(n,m<=50000)。

接下来m行,有如题目所说的三种信息共m条。

输出格式:

对于每一个被围堵的士兵,输出该士兵能够到达的房子数。

输入输出样例

输入样例#1: 复制
7 9
D 3
D 6
D 5
Q 4
Q 5
R
Q 4
R
Q 4
输出样例#1: 复制
1
0
2
4

说明

若士兵被围堵在摧毁了的房子中,那只能等死了。。。。。。

当然这题暴力可过,但是splay也还行

不能把没有摧毁的房子插进去,而是把被摧毁的插进去,这样操作就简单了,因为还有修复,所以要开个栈来保存被摧毁的房子编号

计算房子数的话就先查看当前节点是否在树中,在的话直接输0,否则找前驱与后驱,注意相减后还要减一

初始化时插入0和n+1

还有可能会读入奇奇怪怪的字符,所以读字符时要处理下

  1 #include<stack>
  2 #include<cstdio>
  3 using namespace std;
  4 const int maxn = 5e4+5;
  5 inline int read(){
  6     int x=0,f=1;char ch=getchar();
  7     while(ch>'9'||ch<'0') {if(ch=='-') f=-1;ch=getchar();}
  8     while(ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();}
  9     return x*f;
 10 }
 11 void getc(char &c){//处理字符,第一次没这样做直接爆零(只能说数据坑
 12     c=getchar();
 13     while(c!='D'&&c!='R'&&c!='Q'){
 14         c=getchar();
 15     }
 16 }
 17 stack<int> s;
 18 int ch[maxn][2],par[maxn],size[maxn],val[maxn],cnt[maxn],root,n,m,ncnt;
 19 
 20 void pushup(int x){size[x]=size[ch[x][0]]+size[ch[x][1]]+cnt[x];}
 21 
 22 int chk(int x){return x==ch[par[x]][1];}
 23 
 24 void rotate(int x){
 25     int y=par[x],z=par[y],k=chk(x),w=ch[x][k^1];
 26     ch[y][k]=w;
 27     par[w]=y;
 28     ch[z][chk(y)]=x;
 29     par[x]=z;
 30     ch[x][k^1]=y;
 31     par[y]=x;
 32     pushup(y);
 33     pushup(x);
 34 }
 35 
 36 void splay(int x,int goal=0){
 37     while(par[x]!=goal){
 38         int y=par[x],z=par[y];
 39         if(z!=goal){
 40             if(chk(y)==chk(x)) rotate(y);
 41             else rotate(x);
 42         }
 43         rotate(x);
 44     }
 45     if(!goal) root=x;
 46 }
 47 
 48 void find(int x){
 49     int cur=root;
 50     while(val[cur]!=x&&ch[cur][x>val[cur]]) cur=ch[cur][x>val[cur]];
 51     splay(cur);
 52 }
 53 
 54 int pre(int x){
 55     find(x);
 56     if(val[root]<x) return root;
 57     int cur=ch[root][0];
 58     while(ch[cur][1]) cur=ch[cur][1];
 59     return cur;
 60 }
 61 
 62 int suc(int x){
 63     find(x);
 64     if(val[root]>x) return root;
 65     int cur=ch[root][1];
 66     while(ch[cur][0]) cur=ch[cur][0];
 67     return cur;
 68 }
 69 
 70 void remove(int x){
 71     int last=pre(x),next=suc(x);
 72     splay(last);
 73     splay(next,last);
 74     ch[next][0]=0;
 75 }
 76 
 77 void insert(int x){
 78     int cur=root,fa=0;
 79     while(val[cur]!=x&&cur) fa=cur,cur=ch[cur][x>val[cur]];
 80     if(!cur){
 81         cur=++ncnt;val[cur]=x;
 82         if(fa)
 83         ch[fa][x>val[fa]]=cur;
 84         ch[cur][0]=ch[cur][1]=0;
 85         size[cur]=1;cnt[cur]=1;
 86         par[cur]=fa;
 87     }
 88     else cnt[cur]++;
 89     splay(cur);
 90 }
 91 
 92 int main(){
 93     n=read(),m=read();
 94     insert(0);
 95     insert(n+1);
 96     for(int i=1;i<=m;i++){
 97         char a;getc(a);
 98         if(a=='D'){
 99             int x=read();
100             insert(x);
101             s.push(x);
102         }
103         else if(a=='R'){
104             remove(s.top());
105             s.pop();
106         }
107         else if(a=='Q'){
108             int x=read();
109             find(x);
110             if(val[root]==x) printf("0\n");
111             
112             else {
113                 int succ=suc(x);
114                 int pree=pre(x);
115                 printf("%d\n",val[succ]-val[pree]-1);
116             }
117         }
118     }
119 }
View Code

先写了这两个题,慢慢来。。。。

posted @ 2019-02-15 11:36  plysc  阅读(149)  评论(0编辑  收藏  举报