[bzoj3489][kdtree]A simple rmq problem

2023-10-16 04:08

本文主要是介绍[bzoj3489][kdtree]A simple rmq problem,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Description

因为是OJ上的题,就简单点好了。给出一个长度为n的序列,给出M个询问:在[l,r]之间找到一个在这个区间里只出现过一次的数,并且要求找的这个数尽可能大。如果找不到这样的数,则直接输出0。我会采取一些措施强制在线。

Input

第一行为两个整数N,M。M是询问数,N是序列的长度(N<=100000,M<=200000)
第二行为N个整数,描述这个序列{ai},其中所有1<=ai<=N 再下面M行,每行两个整数x,y,
询问区间[l,r]由下列规则产生(OIER都知道是怎样的吧>_<): l=min((x+lastans)mod
n+1,(y+lastans)mod n+1); r=max((x+lastans)mod n+1,(y+lastans)mod n+1);
Lastans表示上一个询问的答案,一开始lastans为0

Output

一共M行,每行给出每个询问的答案。

Sample Input

10 10

6 4 9 10 9 10 9 4 10 4

3 8

10 1

3 4

9 4

8 1

7 8

2 9

1 1

7 3

9 9

Sample Output

4

10

10

0

0

10

0

4

0

4

HINT

注意出题人为了方便,input的第二行最后多了个空格。

2015.6.24新加数据一组,2016.7.9放至40S,600M,但未重测

题解

发现kdt原来这么强大
原来想了好久可持久化线段树没想到,然后发现做不到。
然后就%了一发发现,原来还有这种操作。
设第i个元素前一个相同元素的位置是pre[i],后一个相同元素的位置是nex[i],元素值为sum[i]
对于l~r,其实就是要找一个l<=i<=r,其中sum[i]最大且pre[i]< l && nex[i]>r
建立三元组(i,pre[i],nex[i]),值即为sum[i]
那么其实就是搞一个三维空间了,三维空间内确定一个范围并找到这个范围内的最大值
切割多维空间就是kdtree啦
在kdtree里进行贪心查找并剪枝即可

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
inline int read()
{int f=1,x=0;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;
}
struct node
{int d[3],mn[3],mx[3],lc,rc;//0 位置 1 pre 2 nex int s,id,pre,nex,smax;
}tr[110000],root;
void upd(int now)
{int lc=tr[now].lc,rc=tr[now].rc;if(lc){for(int i=0;i<3;i++)tr[now].mx[i]=max(tr[now].mx[i],tr[lc].mx[i]),tr[now].mn[i]=min(tr[now].mn[i],tr[lc].mn[i]);tr[now].smax=max(tr[now].smax,tr[lc].smax);}if(rc){for(int i=0;i<3;i++)tr[now].mx[i]=max(tr[now].mx[i],tr[rc].mx[i]),tr[now].mn[i]=min(tr[now].mn[i],tr[rc].mn[i]);tr[now].smax=max(tr[now].smax,tr[rc].smax);}
}
int cmpd;
bool cmp(node n1,node n2){return n1.d[cmpd]<n2.d[cmpd];}
int bt(int l,int r,int d)
{int mid=(l+r)/2;cmpd=d;int now=mid;nth_element(tr+l,tr+mid,tr+r+1,cmp);tr[now].smax=tr[now].s;if(l<mid)tr[now].lc=bt(l,mid-1,(d+1)%3);if(mid<r)tr[now].rc=bt(mid+1,r,(d+1)%3);upd(now);return now;
}
int ql,qr,ans;
bool chk(int now)
{if(now==0)return false;if(tr[now].mx[0]<ql || tr[now].mn[0]>qr)return false;if(tr[now].mn[1]>=ql || tr[now].mx[2]<=qr)return false;return true;
}
void fd(int now)
{if(tr[now].mn[0]>=ql && tr[now].mx[0]<=qr && tr[now].mx[1]<ql && tr[now].mn[2]>qr){ans=max(ans,tr[now].smax);return ;}if(tr[now].id>=ql && tr[now].id<=qr && tr[now].pre<ql && tr[now].nex>qr)ans=max(ans,tr[now].s);int sx=tr[tr[now].lc].smax,sy=tr[tr[now].rc].smax;if(sx>sy){if(tr[now].lc && sx>ans && chk(tr[now].lc))fd(tr[now].lc);if(tr[now].rc && sy>ans && chk(tr[now].rc))fd(tr[now].rc);}else{if(tr[now].rc && sy>ans && chk(tr[now].rc))fd(tr[now].rc);if(tr[now].lc && sx>ans && chk(tr[now].lc))fd(tr[now].lc);}
}
int n,m,a[110000];
int P[110000],N[110000],lastans;
int main()
{n=read();m=read();for(int i=1;i<=n;i++)a[i]=read();for(int i=1;i<=n;i++){tr[i].pre=tr[i].mn[1]=tr[i].mx[1]=tr[i].d[1]=P[a[i]];P[a[i]]=i;}memset(N,63,sizeof(N));for(int i=n;i>=1;i--){tr[i].nex=tr[i].mn[2]=tr[i].mx[2]=tr[i].d[2]=N[a[i]];N[a[i]]=i;}for(int i=1;i<=n;i++)tr[i].s=a[i],tr[i].id=tr[i].d[0]=tr[i].mx[0]=tr[i].mn[0]=i;int root=bt(1,n,0);lastans=0;while(m--){int x=read(),y=read();ql=min((x+lastans)%n+1,(y+lastans)%n+1);qr=max((x+lastans)%n+1,(y+lastans)%n+1);ans=0;fd(root);printf("%d\n",ans);lastans=ans;}return 0;
}

这篇关于[bzoj3489][kdtree]A simple rmq problem的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/218922

相关文章

csu 1446 Problem J Modified LCS (扩展欧几里得算法的简单应用)

这是一道扩展欧几里得算法的简单应用题,这题是在湖南多校训练赛中队友ac的一道题,在比赛之后请教了队友,然后自己把它a掉 这也是自己独自做扩展欧几里得算法的题目 题意:把题意转变下就变成了:求d1*x - d2*y = f2 - f1的解,很明显用exgcd来解 下面介绍一下exgcd的一些知识点:求ax + by = c的解 一、首先求ax + by = gcd(a,b)的解 这个

uva 10014 Simple calculations(数学推导)

直接按照题意来推导最后的结果就行了。 开始的时候只做到了第一个推导,第二次没有继续下去。 代码: #include<stdio.h>int main(){int T, n, i;double a, aa, sum, temp, ans;scanf("%d", &T);while(T--){scanf("%d", &n);scanf("%lf", &first);scanf

uva 10025 The ? 1 ? 2 ? ... ? n = k problem(数学)

题意是    ?  1  ?  2  ?  ...  ?  n = k 式子中给k,? 处可以填 + 也可以填 - ,问最小满足条件的n。 e.g k = 12  - 1 + 2 + 3 + 4 + 5 + 6 - 7 = 12 with n = 7。 先给证明,令 S(n) = 1 + 2 + 3 + 4 + 5 + .... + n 暴搜n,搜出当 S(n) >=

11991 - Easy Problem from Rujia Liu?

题意: 输入一串整型数列,再输入两个数k,v,输出第k个v的序号。不存在则输出0,如第一个样例 8 41 3 2 2 4 3 2 11 3 //第1个3,序号为2,输出22 4 //第2个4,不存在,输出03 2 //第3个2,序号为7,输出74 2 思路: struct num {

HDU 1016 Prime Ring Problem (深搜)

OJ题目 : click here ~~ 大概题意:n个数,形成一个环,使得相邻两个数的和为素数。以1开始,按字典序输出序列。 很简单的深搜。 AC_CODE int n;int visit[22];int num[22];int len;bool Is_prime(int x){for(int i = 2;i*i <= x;i++)if(x%i == 0) return

使用django-simple-captcha遇到的坑

使用django-simple-captcha遇到的坑 一站点gongshare.com在做注册功能时验证码采用的django-simple-captcha,因为笔者开发环境采用的Windows 64bit系统,结果安装使用的时候接二连三遇到好几个坑。 django-simple-captcha需要依赖django1.3+、PIL1.1.7+或者Pillow2.0+,根据文档安装后开始使用时,

LVM 'Can’t open /dev/sdb1 exclusively. Mounted filesystem?' Problem

在将几块盘做LVM时,遇到一个之前都没遇到过的问题: root@ubuntu:~# pvcreate /dev/sdc1Can't open /dev/sdc1 exclusively. Mounted filesystem? 首先第一反应就是查看这个分区是否已经在使用了,但是没有。 查看硬盘的一些信息: root@ubuntu:~# cat /proc/partitionsmajo

HYPERCASUAL - Simple Characters(卡通游戏火柴人物模型)

介绍HyperCasual - 简单角色! 一套低多边形角色资源,用于创建超休闲风格的游戏。 包含演示场景 角色(x10) 生化人、小丑、Flaty_Boss、女孩、守门员、英雄、亚马逊女战士、男人、红衣男人、修理工 每个网格大约有700-2000个顶点 角色设置与Mecanim兼容(本包中不包含动画) 着色器适用于可编写脚本的渲染管线(HD + LW) 下载:​​Unity资源商店链接资源

【HDU】3861 The King’s Problem 强连通缩点+有向图最小路径覆盖

传送门:【HDU】3861 The King’s Problem 题目分析:首先强连通缩点,因为形成一个环的王国肯定在一条路径中,这样才能保证拆的少。 然后缩点后就是DAG图了,由于题目要求的是最小路径覆盖,那么二分匹配即可。 代码如下: #include <cstdio>#include <cstring>#include <algorithm>#includ

【ZOJ】3362 Beer Problem 最小费用流

传送门:【ZOJ】3362 Beer Problem 题目分析:这道题本来应该很快就AC的,但是!因为我以前犯的一个致命错误导致我这题一天了到现在才调出来!唉。。失策。。貌似给的模板也有这个错误。。。马上就去改。。但是这个错误竟然还能过掉那么多的题。。害我还要一题一题的改回去。。 本题就是赤裸裸的最小费用流。 新建汇点t(源点即1),将所有的n-1个城市和汇点建边,容量为无穷大,