【权值分块】bzoj3224 Tyvj 1728 普通平衡树

权值分块和权值线段树的思想一致,离散化之后可以代替平衡树的部分功能。

部分操作的时间复杂度:

插入 删除 全局排名 全局K大 前驱 后继 全局最值
O(1) O(1) O(sqrt(n)) O(sqrt(n)) O(sqrt(n)) O(sqrt(n)) O(sqrt(n))

当然,因为要离散化,所以只能离线。

代码很短,很快,比我的Splay短一倍,快一倍,现在在bzoj上rank6。

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cmath>
 4 using namespace std;
 5 #define N 100001
 6 struct Point{int v,p;}t[N];
 7 bool operator < (const Point &a,const Point &b){return a.v<b.v;}
 8 int n,op[N],a[N],ma[N],en,l[800],r[800],sumv[800],sz,sum,num[N],b[N],Num,CH[12];
 9 inline void R(int &x){
10     char c=0;int f=1;
11     for(;c<‘0‘||c>‘9‘;c=getchar())if(c==‘-‘)f=-1;
12     for(x=0;c>=‘0‘&&c<=‘9‘;c=getchar())(x*=10)+=(c-‘0‘);
13     x*=f;
14 }
15 inline void P(int x)
16 {
17     if(!x){putchar(‘0‘);puts("");return;}
18     if(x<0){putchar(‘-‘);x=-x;}Num=0;
19     while(x>0)CH[++Num]=x%10,x/=10;
20     while(Num)putchar(CH[Num--]+48);puts("");
21 }
22 void makeblock()
23 {
24     sz=sqrt(en); if(!sz) sz=1;
25     for(sum=1;sum*sz<n;sum++)
26       {
27           l[sum]=r[sum-1]+1;
28           r[sum]=sz*sum;
29           for(int i=l[sum];i<=r[sum];i++) num[i]=sum;
30       }
31     l[sum]=r[sum-1]+1;
32     r[sum]=n;
33     for(int i=l[sum];i<=r[sum];i++) num[i]=sum;
34 }
35 inline void Insert(const int &x){b[x]++; sumv[num[x]]++;}
36 inline void Delete(const int &x){b[x]--; sumv[num[x]]--;}
37 inline int Rank(const int &x)
38 {
39     int cnt=0;
40     for(int i=1;i<num[x];i++) cnt+=sumv[i];
41     for(int i=l[num[x]];i<x;i++) cnt+=b[i];
42     return cnt+1;
43 }
44 inline int Kth(const int &x)
45 {
46     int cnt=0;
47     for(int i=1;;i++)
48       {
49           cnt+=sumv[i];
50           if(cnt>=x)
51             {
52                 cnt-=sumv[i];
53             for(int j=l[i];;j++)
54                 {cnt+=b[j]; if(cnt>=x) return j;}
55             }
56       }
57 }
58 inline int Next(const int &x)
59 {
60     for(int i=x+1;i<=r[num[x]];i++) if(b[i]) return i;
61     for(int i=num[x]+1;;i++) if(sumv[i])
62       for(int j=l[i];;j++)
63         if(b[j]) return j;
64 }
65 inline int Pre(const int &x)
66 {
67     for(int i=x-1;i>=l[num[x]];i--) if(b[i]) return i;
68     for(int i=num[x]-1;;i--) if(sumv[i])
69       for(int j=r[i];;j--)
70         if(b[j]) return j;
71 }
72 int main()
73 {
74     R(n); for(int i=1;i<=n;i++)
75       {
76           R(op[i]); R(t[i].v);
77           t[i].p=i;
78       }
79     sort(t+1,t+n+1);
80     ma[a[t[1].p]=++en]=t[1].v;
81     for(int i=2;i<=n;i++)
82       {
83           if(t[i].v!=t[i-1].v) en++;
84           ma[a[t[i].p]=en]=t[i].v;
85       }
86     makeblock();
87     for(int i=1;i<=n;i++)
88       {
89           if(op[i]==1) Insert(a[i]);
90           else if(op[i]==2) Delete(a[i]);
91           else if(op[i]==3) P(Rank(a[i]));
92           else if(op[i]==4) P(ma[Kth(ma[a[i]])]);
93           else if(op[i]==5) P(ma[Pre(a[i])]);
94           else P(ma[Next(a[i])]);
95       }
96     return 0;
97 }
时间: 2024-11-05 02:40:40

【权值分块】bzoj3224 Tyvj 1728 普通平衡树的相关文章

BZOJ3224: Tyvj 1728 普通平衡树[treap]

3224: Tyvj 1728 普通平衡树 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 9046  Solved: 3840[Submit][Status][Discuss] Description 您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:1. 插入x数2. 删除x数(若有多个相同的数,因只删除一个)3. 查询x数的排名(若有多个相同的数,因输出最小的排名)4. 查询排名为x的数5. 求x的前驱(前驱定义为小

【权值线段树】bzoj3224 Tyvj 1728 普通平衡树

一个板子. #include<cstdio> #include<algorithm> using namespace std; #define N 100001 struct Data { int v,p; }t[N]; bool cmp(const Data &a,const Data &b) { return a.v<b.v; } int T[N<<2],op[N],a[N],n,ma[N],e; void Update(int p,int v

bzoj3224 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,

bzoj3224: Tyvj 1728 普通平衡树(打个splay暖暖手)

(其实今天好热啊? 题目大意:插入,删除,k小,前驱后继,数的排名. splay和treap裸题...过几天补个treap的 splay: #include<iostream> #include<cstdlib> #include<cstring> #include<cstdio> using namespace std; const int extar[3]={0,2147483647,-2147483647}; int fa[100010],count[

【Splay】bzoj3224 Tyvj 1728 普通平衡树

#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> using namespace std; #define maxn 1000000 #define INF 2147483647 int n,fa[maxn],val[maxn],c[maxn][2],root,tot,siz[maxn],cnt[maxn]; void Maintain(int x) { siz

【函数式权值分块】【分块】bzoj3196 Tyvj 1730 二逼平衡树

#include<cstdio> #include<cmath> #include<algorithm> using namespace std; #define N 50001 #define SQRT 227 int n,m,xs[N],ys[N],ks[N],op[N],en,ma[100001],en2,a[100001]; int num[N],l[SQRT],r[SQRT],sumv[SQRT],sum=1;//分块 int num2[100001],l2[

【带修莫队】【权值分块】bzoj3196 Tyvj 1730 二逼平衡树

这题用了三种算法写: 分块+二分:O(n*sqrt(n*log(n)) 函数式权值分块:O(n*sqrt(n)) 带修莫队+权值分块:O(n5/3) 结果……复杂度越高的实际上跑得越快……最后这个竟然进第一页了…… #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; int f,C; inline void R(int &

3224: Tyvj 1728 普通平衡树

3224: Tyvj 1728 普通平衡树 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2566  Solved: 1031[Submit][Status] Description 您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:1. 插入x数2. 删除x数(若有多个相同的数,因只删除一个)3. 查询x数的排名(若有多个相同的数,因输出最小的排名)4. 查询排名为x的数5. 求x的前驱(前驱定义为小于x,且最大的数)

【莫队算法】【权值分块】bzoj3920 Yuuna的礼物

[算法一] 暴力. 可以通过第0.1号测试点. 预计得分:20分. [算法二] 经典问题:区间众数,数据范围也不是很大,因此我们可以: ①分块,离散化,预处理出: <1>前i块中x出现的次数(差分): <2>第i块到第j块中的众数是谁,出现了多少次. 询问的时候,对于整块的部分直接获得答案:对于零散的部分,暴力统计每个数出现 的次数,加上差分的结果,尝试更新ans. 时间复杂度O(m*sqrt(n)), 空间复杂度O(n*sqrt(n)). ②考虑离线,莫队算法,转移的时候使用数据