BZOJ - 3489 KD树 范围计数 空间思维转换
题意:给定数列\(a[1...n]\),\(Q\)次查询\([L,R]\)中只出现一次的最大值
这道题的做法比较劲..
对每个元素构造三维空间的点\((i,pre[i],next[i])\),查询\([L,R]\)可以转换为查询\((L≤x≤R,y<L,z>R)\)的区间的最大值
就是说前一个和后一个都不在这个范围内的值
除此以外要注意剪枝!直接按照上面的思路码是会T的
比如随机乱跑,估计一下子树的\(max\)是否比当前答案更优,或者估价边界是否应该搜索(后者我没有写,也就慢个4s..)
#include<bits/stdc++.h>
#define rep(i,j,k) for(register int i=j;i<=k;i++)
#define rrep(i,j,k) for(register int i=j;i>=k;i--)
#define erep(i,u) for(register int i=head[u];~i;i=nxt[i])
#define print(a) printf("%lld",(ll)(a))
#define println(a) printf("%lld\n",(ll)(a))
#define printbk(a) printf("%lld ",(ll)(a))
using namespace std;
const int MAXN = 1e5+11;
const int INF = 0x7fffffff;
typedef long long ll;
ll read(){
ll x=0,f=1;register char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int D;
struct Point{
int x[3],val;
bool operator < (const Point &rhs) const{
return x[D]<rhs.x[D];
}
};
struct KD{
int son[MAXN][2],lx[MAXN][3],rx[MAXN][3];
int size[MAXN];
int mx[MAXN];
Point p[MAXN];
int root,tot;
void pu(int o){
mx[o]=p[o].val;
int lc=son[o][0],rc=son[o][1];
rep(i,0,2){
lx[o][i]=rx[o][i]=p[o].x[i];
if(lc){
if(mx[lc]>mx[o]) mx[o]=mx[lc];
if(lx[lc][i]<lx[o][i]) lx[o][i]=lx[lc][i];
if(rx[lc][i]>rx[o][i]) rx[o][i]=rx[lc][i];
}
if(rc){
if(mx[rc]>mx[o]) mx[o]=mx[rc];
if(lx[rc][i]<lx[o][i]) lx[o][i]=lx[rc][i];
if(rx[rc][i]>rx[o][i]) rx[o][i]=rx[rc][i];
}
}
size[o]=1+size[lc]+size[rc];
}
void init(int n){
root=D=0; tot=n;
}
inline bool inside(int o,int l,int r){
return lx[o][2]>r&&rx[o][1]<l&&lx[o][0]>=l&&rx[o][0]<=r;
}
inline bool outside(int o,int l,int r){
return lx[o][0]>r||rx[o][0]<l||lx[o][1]>=l||rx[o][2]<=r;
}
inline bool in(int o,int l,int r){
int x=p[o].x[0],y=p[o].x[1],z=p[o].x[2];
return x>=l&&x<=r&&y<l&&z>r;
}
/*注意必要的剪枝!*/
// ll query(int o,int l,int r){// l<=x<=r && y<l && z>r //上一个<l 下一个>r
// if(!o) return 0;
// if(inside(o,l,r)) return mx[o];
// if(outside(o,l,r)) return 0;
// ll res=0;
// if(in(o,l,r)) res=p[o].val;
// return max(res,max(query(son[o][0],l,r),query(son[o][1],l,r)));
// }
/*上面这个会T*/
int ANS;
void query(int o,int l,int r){
if(!o) return;
if(inside(o,l,r)){
if(ANS<mx[o]) ANS=mx[o];
return;
}
if(outside(o,l,r)) return;
if(in(o,l,r)&&ANS<p[o].val) ANS=p[o].val;
int lc=son[o][0], rc=son[o][1];
if(mx[lc]>mx[rc]){
if(mx[lc]>ANS) query(lc,l,r); //其实还可以对左右子树多加一个估价函数
if(mx[rc]>ANS) query(rc,l,r);
}else{
if(mx[rc]>ANS) query(rc,l,r);
if(mx[lc]>ANS) query(lc,l,r);
}
}
int build(int now,int l,int r){
int mid=l+r>>1; son[mid][0]=son[mid][1]=0;
D=now; nth_element(p+l,p+mid,p+r+1);
mx[mid]=p[mid].val; size[mid]=1;
rep(i,0,2) lx[mid][i]=rx[mid][i]=p[mid].x[i];
if(l<mid) son[mid][0]=build((now+1)%3,l,mid-1);
if(r>mid) son[mid][1]=build((now+1)%3,mid+1,r);
pu(mid); return mid;
}
ll query(int l,int r){
ANS=0;
query(root,l,r);
return ANS;
}
}kd;
int a[MAXN],pre[MAXN],nxt[MAXN];
int main(){
ll n,m,lastans=0;
while(cin>>n>>m){
rep(i,1,n) pre[i]=-1;
rep(i,1,n) nxt[i]=n+1;
rep(i,1,n) a[i]=read();
rep(i,1,n){
kd.p[i].x[0]=i;
kd.p[i].val=a[i];
kd.p[i].x[1]=pre[a[i]];
pre[a[i]]=i;
}
rrep(i,n,1){
kd.p[i].x[2]=nxt[a[i]];
nxt[a[i]]=i;
}
kd.init(n); kd.root=kd.build(0,1,n);
rep(i,1,m){
int x=read();
int y=read();
int l=min((x+lastans)%n+1,(y+lastans)%n+1);
int r=max((x+lastans)%n+1,(y+lastans)%n+1);
ll res=kd.query(l,r);
println(res);
lastans=res;
}
}
return 0;
}
BZOJ - 3489 KD树 范围计数 空间思维转换的更多相关文章
- BZOJ - 4066 KD树 范围计数 暴力重构
题意:单点更新,大矩阵(\(n*n,n≤10^5\))求和 二维的KD树能使最坏情况不高于\(O(N\sqrt{N})\) 核心在于query时判断当前子树维护的区间是否有交集/当前子节点是否在块中, ...
- BZOJ 1211: [HNOI2004]树的计数( 组合数学 )
知道prufer序列就能写...就是求个可重集的排列...先判掉奇怪的情况, 然后答案是(N-2)!/π(d[i]-1)! -------------------------------------- ...
- bzoj 1211: [HNOI2004]树的计数 -- purfer序列
1211: [HNOI2004]树的计数 Time Limit: 10 Sec Memory Limit: 162 MB Description 一个有n个结点的树,设它的结点分别为v1, v2, ...
- BZOJ - 2648 KD树 最近点查询
省赛后躺尸几天又回来更新了,内容是说好的KD树.. 具体操作从代码中感受一下 感觉已经把KD树尽量封装好了(虽然全局的D看着极不顺眼) 需要注意的是估值函数的判断条件 #include<bits ...
- BZOJ 1211 HNOI2004 树的计数 Prufer序列
题目大意:给定一棵树中全部点的度数,求有多少种可能的树 Prufer序列.详细參考[HNOI2008]明明的烦恼 直接乘会爆long long,所以先把每一个数分解质因数.把质因数的次数相加相减.然后 ...
- bzoj 3244: [Noi2013]树的计数
Description 我们知道一棵有根树可以进行深度优先遍历(DFS)以及广度优先遍历(BFS)来生成这棵树的DFS序以及BFS序.两棵不同的树的DFS序有可能相同,并且它们的BFS序也有可能相同, ...
- BZOJ 1211[HNOI2004]树的计数 - prufer数列
描述 一个有n个结点的树,设它的结点分别为v1, v2, …, vn,已知第i个结点vi的度数为di,问满足这样的条件的不同的树有多少棵.给定n,d1, d2, …, dn,编程需要输出满足d(vi) ...
- 【刷题】BZOJ 1211 [HNOI2004]树的计数
Description 一个有n个结点的树,设它的结点分别为v1, v2, -, vn,已知第i个结点vi的度数为di,问满足这样的条件的不同的树有多少棵.给定n,d1, d2, -, dn,编程需要 ...
- bzoj 1211: [HNOI2004]树的计数
prufer的应用.. 详细见这篇博客:https://www.cnblogs.com/dirge/p/5503289.html import java.math.BigInteger; import ...
随机推荐
- 661. Image Smoother色阶中和器
[抄题]: Given a 2D integer matrix M representing the gray scale of an image, you need to design a smoo ...
- dpdk中kni模块
一,什么是kni,为什么要有kni Kni(Kernel NIC Interface)内核网卡接口,是DPDK允许用户态和内核态交换报文的解决方案,模拟了一个虚拟的网口,提供dpdk的应用程序和lin ...
- 利用AdaBoost方法构建多个弱分类器进行分类
1.AdaBoost 思想 补充:这里的若分类器之间有比较强的依赖关系;对于若依赖关系的分类器一般使用Bagging的方法 弱分类器是指分类效果要比随机猜测效果略好的分类器,我们可以通过构建多个弱分类 ...
- Spring下面的@Transactional注解标志的讲解
最近在开发中对Spring中的事务标记@Transactional用的比较多,今天上网收集了一些内容,做一个简单的总结~~~ 在service类前加上@Transactional,声明这个servic ...
- SVN常见问题及解决方式(二)
1.分支不同 ==> update merge(svn自动合并)2.分支冲突 ==> 协商解决冲突,选择一个正确的版本覆盖(最新的正确直接Revert最新):出现四个文件.黄色感叹号代表S ...
- WEB测试和APP测试区别
Web测试和App测试从流程上来说,没有区别.都需要经历测试计划方案,用例设计,测试执行,缺陷管理,测试报告等相关活动.从技术上来说,WEB测试和APP测试其测试类型也基本相似,都需要进行功能测试.性 ...
- C++中的Trivial 、POD、non-POD和Standard Layout概念
POD types non-POD types Standard Layout types A Formal Definition Informally, a standard layout clas ...
- 【Android学习】实现卡片式ListView
效果: 主要是设置xml文件 两种状态下的item card_background.xml <?xml version="1.0" encoding="utf-8& ...
- 学习React中遇到的问题
1.执行eject后,再次启动项目报错 情景:使用create-react-app搭建了项目,启动没有问题,然后执行 $ yarn eject 暴露出webpack配置文件等,再次 $ yarn st ...
- Live 直播过程
采集.处理.编码.封包.推流.传输.转码.分发.拉流.解码.播放,从推流到播放