BZOJ 3224 Tyvj 1728 普通平衡树

3224: Tyvj 1728 普通平衡树

Description

您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:
1. 插入x数
2. 删除x数(若有多个相同的数,因只删除一个)
3. 查询x数的排名(若有多个相同的数,因输出最小的排名)
4. 查询排名为x的数
5. 求x的前驱(前驱定义为小于x,且最大的数)
6. 求x的后继(后继定义为大于x,且最小的数)

Input

第一行为n,表示操作的个数,下面n行每行有两个数opt和x,opt表示操作的序号(1<=opt<=6)

Output

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

Sample Input

10
1 106465
4 1
1 317721
1 460929
1 644985
1 84185
1 89851
6 81968
1 492737
5 493598

Sample Output

106465
84185
492737

HINT

1.n的数据范围:n<=100000

2.每个数的数据范围:[-2e9,2e9]

   第一次这么仔细的打平衡树。但方法绝不仅仅止于此。
  因为是裸题,所以可以用:
  • 树状数组fenwick
  • 线段树(因为树状数组可以)
  • 近乎于暴力的vector
  • 平衡树家族
    • 红黑树rbt
    • 节点大小平衡树sbt
    • splay
    • 替罪羊树sgt
    • treap  
  1 /**************************************************************
  2     Problem: 3224
  3     User: Doggu
  4     Language: C++
  5     Result: Accepted
  6     Time:304 ms
  7     Memory:3164 kb
  8 ****************************************************************/
  9  
 10 #include <cstdio>
 11 #include <cmath>
 12 #include <algorithm>
 13 #define sm(a,b,c) {if(c==0) a=std::max(a,b);else a=std::min(a,b);}
 14 template<class T> inline void readin(T &res) {
 15     static char ch;T flag=1;
 16     while((ch=getchar())<48||ch>57)if(ch=='-')flag=-1;
 17     res=ch-48;
 18     while((ch=getchar())>=48&&ch<=57)res=(res<<1)+(res<<3)+ch-'0';
 19     res*=flag;
 20 }
 21 const int N = 100005;
 22 const int INF = 0x3f3f3f3f;
 23 struct Node {
 24     int key, w, size, rd;
 25     Node *ch[2];
 26     int cmp(int x) {
 27         if(x==key) return -1;
 28         return x>key;
 29     }
 30     void maintain() {size = ch[0]->size + ch[1]->size + w;}
 31 }pool[N], *tail=pool, *root=pool, *null=pool;
 32 int rand() {
 33     static int seed=1000007;
 34     return seed=(int)seed*48271LL%2147483647;
 35 }
 36 Node* newnode() {
 37     Node *nd = tail++;
 38     nd->rd=rand();nd->ch[0]=nd->ch[1]=null;
 39     return nd;
 40 }
 41 void rotate(Node *&nd,int d) {//d=0 right(1) to left(0) d=1 left(0) to right(1)
 42     Node *k=nd->ch[d^1];nd->ch[d^1]=k->ch[d];k->ch[d]=nd;
 43     nd->maintain();k->maintain();nd=k;
 44 }
 45 void insert(Node *&nd,int x) {
 46     if(nd==null) nd=newnode(),nd->key=x,nd->w=1;
 47     else {
 48         int d=nd->cmp(x);
 49         if(d==-1) nd->w++;
 50         else {
 51             insert(nd->ch[d],x);
 52             if(nd->ch[d]->rd>nd->rd) rotate(nd,d^1);
 53         }
 54     }
 55     nd->maintain();
 56 }
 57 void del(Node *&nd,int x) {
 58     if(nd==null) return ;
 59     int d=nd->cmp(x);
 60     if(d==-1) {
 61         if(nd->w>1) nd->w--;
 62         else if(nd->ch[0] == null) nd=nd->ch[1];
 63         else if(nd->ch[1] == null) nd=nd->ch[0];
 64         else if(nd->ch[1]>nd->ch[0]) rotate(nd,0),del(nd->ch[0],x);
 65         else rotate(nd,1),del(nd->ch[1],x);
 66     } else del(nd->ch[d],x);
 67     nd->maintain();
 68 }
 69 int find(Node *nd,int x) {
 70     while(nd!=null) {
 71         int d=nd->cmp(x);
 72         if(d==-1) return 1;
 73         nd=nd->ch[d];
 74     }
 75     return 0;
 76 }
 77 int rnk(Node *nd,int x) {
 78     int d=nd->cmp(x);
 79     if(d==-1) return nd->ch[0]->size+1;
 80     if(d==0) return rnk(nd->ch[0],x);
 81     return nd->ch[0]->size+nd->w+rnk(nd->ch[1],x);
 82 }
 83 int kth(Node *nd,int x) {
 84     if(x<=nd->ch[0]->size) return kth(nd->ch[0],x);
 85     if(nd->ch[0]->size<x && x<=nd->ch[0]->size+nd->w) return nd->key;
 86     return kth(nd->ch[1],x-nd->ch[0]->size-nd->w);
 87 }
 88 int temp;
 89 void near(Node *nd,int x,int delta) {
 90     if(nd==null) return ;
 91     int d=nd->cmp(x);
 92     if(d==!delta) sm(temp,nd->key,delta);
 93     if(d==-1) near(nd->ch[delta],x,delta);
 94     else near(nd->ch[d],x,delta);
 95 }
 96  
 97 /*void print(Node *nd) {
 98     if(nd==null) return ;
 99     print(nd->ch[0]);
100     for( int i = 1; i <= nd->w; i++ ) printf("%d ",nd->key);
101     print(nd->ch[1]);
102 }*/
103  
104 int main() {
105     //freopen("in.txt","r",stdin);
106     //freopen("out.txt","w",stdout);
107     null=newnode();
108     int n, opt, x;
109     readin(n);
110     for( int i = 1; i <= n; i++ ) {
111         readin(opt);readin(x);
112         if(opt==1) {//插入x数
113             insert(root,x);
114         }else if(opt==2) {//删除x数(若有多个相同的数,因只删除一个)
115             del(root,x);
116         }else if(opt==3) {//查询x数的排名(若有多个相同的数,因输出最小的排名)
117             if(find(root,x)) printf("%d\n",rnk(root,x));
118         }else if(opt==4) {//查询排名为x的数
119             if(root->size>=x) printf("%d\n",kth(root,x));
120         }else if(opt==5) {//求x的前驱
121             temp=-INF;near(root,x,0);if(temp!=-INF)printf("%d\n",temp);
122         }else if(opt==6) {//求x的后继 
123             temp=INF;near(root,x,1);if(temp!=INF)printf("%d\n",temp);
124         }
125         //printf("SEQ:");print(root);putchar('\n');
126     }
127     return 0;
128 }
129 
TREAP

 

转载于:https://www.cnblogs.com/Doggu/p/bzoj3224.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
题目描述 有一个 $n$ 个点的棋盘,每个点上有一个数字 $a_i$,你需要从 $(1,1)$ 走到 $(n,n)$,每次只能往右或往下走,每个格子只能经过一次,路径上的数字和为 $S$。定义一个点 $(x,y)$ 的权值为 $a_x+a_y$,求所有满足条件的路径中,所有点的权值和的最小值。 输入格式 第一行一个整数 $n$。 接下来 $n$ 行,每行 $n$ 个整数,表示棋盘上每个点的数字。 输出格式 输出一个整数,表示所有满足条件的路径中,所有点的权值和的最小值。 数据范围 $1\leq n\leq 300$ 输入样例 3 1 2 3 4 5 6 7 8 9 输出样例 25 算法1 (树形dp) $O(n^3)$ 我们可以先将所有点的权值求出来,然后将其看作是一个有权值的图,问题就转化为了在这个图中求从 $(1,1)$ 到 $(n,n)$ 的所有路径中,所有点的权值和的最小值。 我们可以使用树形dp来解决这个问题,具体来说,我们可以将这个图看作是一棵树,每个点的父节点是它的前驱或者后继,然后我们从根节点开始,依次向下遍历,对于每个节点,我们可以考虑它的两个儿子,如果它的两个儿子都被遍历过了,那么我们就可以计算出从它的左儿子到它的右儿子的路径中,所有点的权值和的最小值,然后再将这个值加上当前节点的权值,就可以得到从根节点到当前节点的路径中,所有点的权值和的最小值。 时间复杂度 树形dp的时间复杂度是 $O(n^3)$。 C++ 代码 算法2 (动态规划) $O(n^3)$ 我们可以使用动态规划来解决这个问题,具体来说,我们可以定义 $f(i,j,s)$ 表示从 $(1,1)$ 到 $(i,j)$ 的所有路径中,所有点的权值和为 $s$ 的最小值,那么我们就可以得到如下的状态转移方程: $$ f(i,j,s)=\min\{f(i-1,j,s-a_{i,j}),f(i,j-1,s-a_{i,j})\} $$ 其中 $a_{i,j}$ 表示点 $(i,j)$ 的权值。 时间复杂度 动态规划的时间复杂度是 $O(n^3)$。 C++ 代码

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值