Codeforces 840D Destiny 【主席树】
2017-08-20 21:58
405 查看
题目地址:点击打开链接
先考虑问题的简化版。假设l和r固定不变,由于数字范围同样是1到n,故我们可以考虑用线段树维护一个计数表(统计1有多少个,2有多少个,3有多少个,。。。),每个点的权值表示值在区间[l,r]之间的数的个数。
那么对于每次查询的k,先计算出((r-l+1)/k)+1(记为P),那么目标就是从线段树中找出权值大于等于P的最左边的叶子节点。
直接从线段树的顶部开始往下搜,如果搜到最底部的话便返回当前叶子节点代表的数值,否则如果左边分支的权值大于等于P则往左边搜下去,如果左边分支的权值小于P或者左边搜下去的返回值为-1,则往右边分支搜(如果右边分支的权值大于等于P的话)。如果两边都搜不到结果或者小于P的话则返回-1,否则优先返回左边搜到的结果。
可以通过极端情况推导的方法(或者强有力的直觉)来得知,在2<=k<=5的范围内,每次查询的时间复杂度差不多是O(logn)。
而对于原问题而言,只需要按照数列的顺序从左到右维护一棵主席树,然后每次要查询的线段树便是第r次更新的线段树减去第l-1次更新的线段树。
代码如下:
先考虑问题的简化版。假设l和r固定不变,由于数字范围同样是1到n,故我们可以考虑用线段树维护一个计数表(统计1有多少个,2有多少个,3有多少个,。。。),每个点的权值表示值在区间[l,r]之间的数的个数。
那么对于每次查询的k,先计算出((r-l+1)/k)+1(记为P),那么目标就是从线段树中找出权值大于等于P的最左边的叶子节点。
直接从线段树的顶部开始往下搜,如果搜到最底部的话便返回当前叶子节点代表的数值,否则如果左边分支的权值大于等于P则往左边搜下去,如果左边分支的权值小于P或者左边搜下去的返回值为-1,则往右边分支搜(如果右边分支的权值大于等于P的话)。如果两边都搜不到结果或者小于P的话则返回-1,否则优先返回左边搜到的结果。
可以通过极端情况推导的方法(或者强有力的直觉)来得知,在2<=k<=5的范围内,每次查询的时间复杂度差不多是O(logn)。
而对于原问题而言,只需要按照数列的顺序从左到右维护一棵主席树,然后每次要查询的线段树便是第r次更新的线段树减去第l-1次更新的线段树。
代码如下:
#include <bits/stdc++.h> using namespace std; #define sfi(a) scanf("%d",&a) #define sfd(a) scanf("%lf",&a) #define sfl(a) scanf("%lld",&a) #define sfs(a) scanf("%s",a) #define rep(i,a,b) for(int i=int(a);i<int(b);++i) #define dwn(i,b,a) for(int i=int(b-1);i>=int(a);--i) #define mem(a,p) memset(a,p,sizeof(a)) typedef long long LL; typedef unsigned UINT; typedef unsigned long long ULL; struct Chairman_Tree { struct node { int l,r; int cnt; void init() { l=r=-1; cnt=0; } }; node a[7000005]; int top; int root[300005]; int rtop; int n; void BuildTree(int l,int r,int p) { a[p].init(); if(l==r)return; int mid=(l+r)>>1; a[p].l=top++; BuildTree(l,mid,a[p].l); a[p].r=top++; BuildTree(mid+1,r,a[p].r); } void init(int nn) { n=nn; top=1; BuildTree(1,n,0); rtop=1; root[0]=0; } void Add(int e) { a[top].init(); a[top].cnt=a[root[rtop-1]].cnt+1; root[rtop]=top; top++;rtop++; int p1=root[rtop-2],p2=root[rtop-1]; int l=1,r=n; while(r-l) { int mid=(l+r)>>1; if(e<=mid) { a[p2].r=a[p1].r; a[p2].l=top; top++; p2=a[p2].l; p1=a[p1].l; a[p2].init(); a[p2].cnt=a[p1].cnt+1; r=mid; } else { a[p2].l=a[p1].l; a[p2].r=top; top++; p2=a[p2].r; p1=a[p1].r; a[p2].init(); a[p2].cnt=a[p1].cnt+1; l=mid+1; } } } int DFS(int p1,int p2,int cnt,int l,int r) { if(a[p2].cnt-a[p1].cnt<cnt)return -1; if(l==r)return l; int mid=(l+r)>>1; int ans=DFS(a[p1].l,a[p2].l,cnt,l,mid); if(ans==-1)ans=DFS(a[p1].r,a[p2].r,cnt,mid+1,r); return ans; } int Query(int l,int r,int k) { int p1=root[l-1],p2=root[r]; int cnt=((r-l+1)/k)+1; return DFS(p1,p2,cnt,1,n); } void Print() { printf("******************************\n"); printf("RootList: "); rep(i,0,rtop)printf("%d ",root[i]); printf("\n"); rep(i,0,top) { printf("%d: \tl=%d \tr=%d \tcnt=%d\n",i,a[i].l,a[i].r,a[i].cnt); } printf("******************************\n"); } }C; int main() { int n,q; while(scanf("%d%d",&n,&q)==2) { C.init(n); rep(i,0,n) { int p; sfi(p); C.Add(p); } rep(i,0,q) { int l,r,k; scanf("%d%d%d",&l,&r,&k); printf("%d\n",C.Query(l,r,k)); } } }
相关文章推荐
- codeforces 840D Destiny 主席树
- [主席树] Codeforces 840D .Destiny
- CodeForces - 840D:(主席树求出现区间出现次数大于某值的最小数)
- codeforces 840D 主席树
- Codeforces 840D [主席树]
- codeforces840D Destiny -- 可持久化线段树
- Codeforces 813E Army Creation 主席树(在线,求[l,r]内比x大的数的个数)
- Codeforces 813E Army Creation 主席树(在线,求[l,r]内比x大的数的个数)
- CodeForces - div1 -650D:Zip-line(主席树 占位)
- Codeforces 813E Army Creation 主席树(在线,求[l,r]内比x大的数的个数)
- 【Codeforces 597C】 Subsequences - DP 主席树
- CodeForces 547E:Mike and Friends(AC自动机+DFS序+主席树)
- Codeforces 813E Army Creation 主席树(在线,求[l,r]内比x大的数的个数)
- Codeforces 813E Army Creation 主席树(在线,求[l,r]内比x大的数的个数)
- CodeForces 547E Mike and Friends AC自动机 主席树
- codeforces Div.2 #840D Leha and another game about graph 顶点权值为度数对应奇偶
- Codeforces 707D Persistent Bookcase(离线dfs或在线主席树)
- Codeforces 453E Little Pony and Lord Tirek (Splay + 主席树)
- 【暴力讨论+主席树】Codeforces 853C Boredom
- CodeForces - 597C:Subsequences (主席树+DP)