【BZOJ】【3489】A simple rmq problem

KD-Tree(乱搞)



  Orz zyf教给蒟蒻做法

  蒟蒻并不会这题正解……(可持久化树套树?。。。Orz

  对于每个点,我们可以求出pre[i],nex[i],那么询问的答案就是:求max (a[i]),其中 i 满足$ ( pre[i]<ql \ and \ nex[i]>qr\ and\ i \in [ql,qr] ) $

  然后我们以(i,pre[i],nex[i])为坐标……将所有点抽象到三维空间中,每次查询就相当于是一次区域求最值!

这题我的感受:

因为前面做了两道区域求和的……然后思路不由自主又代入到搞【子树最大值】来更新答案……然而忘记了单点更新,也就是:虽然这个子树不合法,但是这一个点(根)还是可能合法的……

然后就是:KD-Tree如果可以搞整个子树的话,那么用整个子树的最值去更新,会优化很多……?

终于1A了一道KD-Tree啦~好开心(虽然不是自己想出的做法……)

一个更加优秀的做法:http://www.cnblogs.com/mhy12345/p/4517347.html

  1 /**************************************************************
  2     Problem: 3489
  3     User: Tunix
  4     Language: C++
  5     Result: Accepted
  6     Time:3712 ms
  7     Memory:7920 kb
  8 ****************************************************************/
  9
 10 //BZOJ 3489
 11 #include<cstdio>
 12 #include<cstring>
 13 #include<cstdlib>
 14 #include<iostream>
 15 #include<algorithm>
 16 #define rep(i,n) for(int i=0;i<n;++i)
 17 #define F(i,j,n) for(int i=j;i<=n;++i)
 18 #define D(i,j,n) for(int i=j;i>=n;--i)
 19 #define pb push_back
 20 using namespace std;
 21 typedef long long LL;
 22 inline int getint(){
 23     int r=1,v=0; char ch=getchar();
 24     for(;!isdigit(ch);ch=getchar()) if (ch==‘-‘) r=-1;
 25     for(; isdigit(ch);ch=getchar()) v=v*10-‘0‘+ch;
 26     return r*v;
 27 }
 28 const int N=100010,INF=1e9;
 29 /*******************template********************/
 30 int n,m,D,a[N],root,ans,now[N],nex[N],pre[N];
 31 struct node{
 32     int d[3],mn[3],mx[3],l,r,v,vmax;
 33     int& operator [] (int i) {return d[i];}
 34 }t[N];
 35 //d[0] 下标
 36 //d[1] nex
 37 //d[2] pre
 38 bool operator < (node a,node b){return a[D]<b[D];}
 39
 40 #define L t[o].l
 41 #define R t[o].r
 42 #define mid (l+r>>1)
 43 void Push_up(int o){
 44     F(i,0,2){
 45         t[o].mn[i]=min(t[o][i],min(t[L].mn[i],t[R].mn[i]));
 46         t[o].mx[i]=max(t[o][i],max(t[L].mx[i],t[R].mx[i]));
 47     }
 48     t[o].vmax=max(t[o].v,max(t[L].vmax,t[R].vmax));
 49 }
 50
 51 int build(int l,int r,int dir){
 52     D=dir;
 53     nth_element(t+l,t+mid,t+r+1);
 54     int o=mid;
 55     L = l < mid ? build(l,mid-1,(dir+1)%3) : 0;
 56     R = mid < r ? build(mid+1,r,(dir+1)%3) : 0;
 57     Push_up(o);
 58     return o;
 59 }
 60 int ql,qr;
 61 inline bool check(int o){
 62     if (!o) return 0;
 63     if (t[o].mx[1]<=qr || t[o].mn[2]>=ql) return 0;
 64     if (t[o].mn[0]>qr || t[o].mx[0]<ql) return 0;
 65     return 1;
 66 }
 67 void query(int o){
 68     if (!o) return;
 69     if (t[o].mn[0]>=ql && t[o].mx[0]<=qr && t[o].mn[1]>qr && t[o].mx[2]<ql){
 70         ans=max(ans,t[o].vmax);
 71         return;
 72     }
 73     if (t[o][0]>=ql && t[o][0]<=qr && t[o][1]>qr && t[o][2]<ql)
 74         ans=max(ans,t[o].v);
 75     if (t[L].vmax>t[R].vmax){
 76         if (t[L].vmax>ans && check(L)) query(L);
 77         if (t[R].vmax>ans && check(R)) query(R);
 78     }else{
 79         if (t[R].vmax>ans && check(R)) query(R);
 80         if (t[L].vmax>ans && check(L)) query(L);
 81     }
 82 }
 83 int main(){
 84 #ifndef ONLINE_JUDGE
 85     freopen("3489.in","r",stdin);
 86     freopen("3489.out","w",stdout);
 87 #endif
 88     F(i,0,2) t[0].mn[i]=INF,t[0].mx[i]=-INF;
 89     t[0].vmax=-1;
 90     n=getint(); m=getint();
 91     F(i,1,n) a[i]=getint();
 92     F(i,1,n){
 93         pre[i]=now[a[i]];
 94         now[a[i]]=i;
 95     }
 96     F(i,1,n) nex[pre[i]]=i;
 97     F(i,1,n) if (!nex[i]) nex[i]=n+1;
 98     F(i,1,n) t[i][0]=i,t[i][1]=nex[i],t[i][2]=pre[i],t[i].v=a[i];
 99     root=build(1,n,0);
100     F(i,1,m){
101         int x=getint(),y=getint();
102         ql=min( (x+ans)%n+1,(y+ans)%n+1);
103         qr=max( (x+ans)%n+1,(y+ans)%n+1);
104         ans=0;
105         query(root);
106         printf("%d\n",ans);
107     }
108     return 0;
109 }

3489: A simple rmq problem

Time Limit: 10 Sec  Memory Limit: 512 MB
Submit: 554  Solved: 173
[Submit][Status][Discuss]

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的第二行最后多了个空格。

Source

by zhzqkkk

[Submit][Status][Discuss]

时间: 2024-08-24 08:21:50

【BZOJ】【3489】A simple rmq problem的相关文章

P2433 - 【BZOJ 3262三维偏序】陌上花开------三维偏序

P2433 - [BZOJ 3262三维偏序]陌上花开 Description 有n朵花,每朵花有三个属性:花形(s).颜色(c).气味(m),又三个整数表示.现要对每朵花评级,一朵花的级别是它拥有的美丽能超过的花的数量. 定义一朵花A比另一朵花B要美丽,当且仅当Sa>=Sb,Ca>=Cb,Ma>=Mb.显然,两朵花可能有同样的属性.需要统计出评出每个等级的花的数量. Input 第一行为N,K (1 <= N <= 100,000, 1 <= K <= 200,

【BZOJ3489】A simple rmq problem kd-tree

[BZOJ3489]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行,每

【BZOJ做题记录】07.07~?

在NOI一周前重开一个坑 最后更新时间:7.07 11:26 7.06 下午做的几道CQOI题: BZOJ1257: [CQOI2007]余数之和sum:把k mod i写成k-k/i*i然后分段求后面的部分就好了 BZOJ1258: [CQOI2007]三角形tri:在草稿纸上按照位置和边找一下规律就好了 BZOJ1260: [CQOI2007]涂色paint:简单的区间DP BZOJ1303: [CQOI2009]中位数图:小于中位数的改为-1大于的改为1,算一算前缀和然后哈希一下乘一乘就好

[BZOJ 3489] A simple rmq problem 【可持久化树套树】

题目链接:BZOJ - 3489 题目分析 “因为是OJ上的题,就简单点好了.”——出题人 真的..好..简单... 首先,我们求出每个数的前一个与它相同的数的位置,即 prev[i] ,如果前面没有相同的数,prev[i] = 0. 再求出每个数的后一个与它相同的数的位置,即 next[i], 如果后面没有相同的数,next[i] = n + 1. 这样,对于 l > prev[i], r < next[i] 的区间,i 这个数在区间中至多出现一次. 那么我们要求的就是:符合 prev[i]

【kd-tree】bzoj3489 A simple rmq problem

Orz zyf教给蒟蒻做法 蒟蒻并不会这题正解……(可持久化树套树?...Orz 对于每个点,我们可以求出pre[i],nex[i],那么询问的答案就是:求max (a[i]),其中 i 满足(pre[i]<ql and nex[i]>qr and i∈[ql,qr]) 然后我们以(i,pre[i],nex[i])为坐标……将所有点抽象到三维空间中,每次查询就相当于是一次区域求最值! 这题我的感受: 因为前面做了两道区域求和的……然后思路不由自主又代入到搞[子树最大值]来更新答案……然而忘记了

【bzoj3489】 A simple rmq problem k-d树

由于某些原因,我先打了一个错误的树套树,后来打起了$k-d$.接着因不明原因在思路上被卡了很久,在今天中午蹲坑时恍然大悟...... 对于一个数字$a_i$,我们可以用一组三维坐标$(i,pre,nxt)$来表示,其中$i$表示该数字下标,$pre$表示在区间$[1,i)$中满足$a[j]=a[i]$的最大$j$,若不存在,则$pre=0$.$nxt$表示在区间$(i,n]$中满足$a[j]=a[i]$的最小$j$,若不存在,则$nxt=n+1$. 接着我们种一棵3-d树去存储这n个点.对于任意

【bzoj3489】A simple rmq problem

Portal -->bzoj3489 Solution 最近计划智力康复qwq(话说这题一年前刚刚开始写树套树的时候感觉好难啊qwq现在看其实还好也算是有进步的嘛!) 比较重要的一步是,要将"在\([l,r]\)中只出现一次"这个条件转化成"\(nxt[x]>r\)&&\(pre[x]<l\)",其中\(nxt[x]\)表示下一个出现位置\(x\)的数的位置,\(pre[x]\)表示前一个 然后我们就发现其实是有三个限制: 1.\(

bzoj 3489 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

bzoj 3489 A simple rmq problem —— 主席树套线段树

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3489 题解:http://www.itdaan.com/blog/2017/11/24/9bc46b690756fe252e17fc3ca90aa01.html 在我挣扎一下午时 Narh 早就A了... 于是看看有何不同,发现 add  和 insert 中必须把 ls[x] = ls[y] , rs[x] = rs[y] 写在前面,而不能是修改 rs 则在那里单写一个 ls[x] =