POJ 2104 K-th Number (划分树,主席树写过了,这次是整体二分解法 )
来源:互联网 发布:矩阵迹的性质及证明 编辑:程序博客网 时间:2024/05/21 10:01
还是先描述一下题意:
给出一个长度为n的数列,m次询问区间内的第k大数
对划分树,主席树和整体二分通过这题做了一下比较
划分树 1000ms+
主席树 2000ms+
整体二分 1500ms+
整体二分介于两者之前,对于这题复杂度约莫是O( (n+m)log(n+m)log( Range( ans ) ) )
整体二分这个东西比较奇妙,运用的是离线算法,而主席树和划分树都是在线的
先引用一下2013年许昊然论文-《浅谈数据结构题的几个非经典解法》解释一下整体二分
此题整体二分思路:
1.确定答案在l~r这个区间内
2.取二分中值mid,询问所有查询操作在数组中小于等于mid的情况下,有多少个数在查询区间内
3.由此将查询分为两类
q1: 区间内个数大于等于k
q2:区间内个数小于k
可以看出q1情况下的查询应该缩小答案,q2情况下的查询应该放大答案,
同时q2情况下记录mid对对答案的影响值cur(有点类似于cdq分治思想)
由此为依据对数组值和查询操作一起进行二分,回到步骤1一直到得到所有答案
此处统计个数用树状数组简洁方便
#include<cstdio>#include<cstring>#include<algorithm>#include<queue>#include<string>#include<iostream>using namespace std;#define INF 0x3f3f3f3fstruct node{ int l,r,k,val; int cur,index; int kind;} q[200005],q1[100005],q2[100005];int n,m;int ans[100006];int c[100006];int tmp[200006];void init(){ memset(c,0,sizeof c); memset(tmp,0,sizeof tmp); for(int i=1; i<=m+n; i++) { q[i].cur=q1[i].cur=q2[i].cur=0; }}inline int lowbit(int x){ return x&-x;}inline void update(int x,int val){ for(; x<=n; x+=lowbit(x)) c[x]+=val;}inline int query(int x){ int sum=0; for(; x>0; x-=lowbit(x)) sum+=c[x]; return sum;}void divide(int s,int t,int l,int r){ if(s>t) return ; if(l==r) { for(int i=s; i<=t; i++) if(q[i].kind==2) ans[q[i].index]=l; return ; } int mid=(l+r)>>1; int num1=0,num2=0,flag1=0,flag2=0; for(int i=s; i<=t; i++) { if(q[i].kind==1) { if(q[i].val<=mid) update(q[i].index,1),q1[num1++]=q[i]; else q2[num2++]=q[i]; } else if(q[i].kind==2) { tmp[i]=query(q[i].r)-query(q[i].l-1); if(q[i].cur+tmp[i]>=q[i].k) q1[num1++]=q[i],flag1=1; else q[i].cur+=tmp[i],q2[num2++]=q[i],flag2=1; } } for(int i=s; i<=t; i++) { if(q[i].kind==1&&q[i].val<=mid) update(q[i].index,-1); } for(int i=0; i<num1; i++) q[s+i]=q1[i]; for(int i=0; i<num2; i++) q[s+num1+i]=q2[i]; if(flag1) divide(s,s+num1-1,l,mid); if(flag2) divide(s+num1,t,mid+1,r);}int main(){ while(scanf("%d%d",&n,&m)!=EOF) { init(); int cnt=1; for(int i=1; i<=n; i++) { scanf("%d",&q[cnt].val); q[cnt].kind=1; q[cnt].index=i; cnt++; } for(int i=1; i<=m; i++) { q[cnt].index=i; scanf("%d%d%d",&q[cnt].l,&q[cnt].r,&q[cnt].k); q[cnt].kind=2; cnt++; } divide(1,cnt-1,-INF,INF); for(int i=1; i<=m; i++) printf("%d\n",ans[i]); } return 0;}
0 0
- POJ 2104 K-th Number (划分树,主席树写过了,这次是整体二分解法 )
- Poj 2104 K-th Number(主席树&&整体二分)
- POJ 2104 K-th Number (主席树 || 划分树)
- POJ 2104 K-th Number (划分树 / 主席树)
- [POJ]2104 K-th Number 主席树&线段树合并&整体二分
- 【POJ 2104/HDU 2665】K-th Number【整体二分/主席树】
- poj 2104 K-th Number(划分树 or 主席树)
- poj 2104 K-th Number(划分树裸题&主席树)
- [POJ 2104]K-th Number 主席树
- poj 2104 K-th Number (主席树)
- poj 2104 K-th Number【主席树】
- POJ 2104 K-th Number [主席树]
- POJ 2104 K-th Number 主席树
- 主席树 poj 2104 K-th Number
- POJ 2104 K-th Number 主席树
- POJ 2104 K-th Number(主席树)
- 【POJ 2104 K-th Number】+ 主席树
- 【POJ】2104 K-th Number 主席树
- js获取子节点childNodes和children的区别
- 一个简单java程序的运行全过程
- 贪心算法——寻找剩余最大数
- 酒店管理系统_06_-Servlet版本-添加用户数据
- 基于BASE64原理编码解码实现-----C语言
- POJ 2104 K-th Number (划分树,主席树写过了,这次是整体二分解法 )
- LeetCode - 367. Valid Perfect Square
- 酒店管理系统_07-Servlet版本-用户列表和删除用户-EL表达式
- Java 集合系列12之 TreeMap详细介绍(源码解析)和使用示例
- POJ-2981 Strange Way to Express Integers(中国剩余定理)
- java基于ssm框架整合的多数据源配置
- PreparedStatement的使用
- Java每一天4 Thinking P268
- BTace系列之一:BTrace工具简介