51Nod 1571 最近等对(线段树、离线查询)

http://www.51nod.com/Challenge/Problem.html#!#problemId=1571

题解

题目要求的最近点对不太符合区间加合性,所以不能直接用线段树在线做。

我们可以先把数据离散化,求出当前点左边离他最近的点的位置,从左到右扫一遍,更新当前点的距离,然后回答以当前点为右端点的查询,题目数据量很大必须快读快写,换行不能用priintf("\n"),只能用putchar(‘\n‘);不然会慢一倍然后T掉好几个数据。。。

  1 #define dbg(x) cout<<#x<<" = "<< (x)<< endl
  2 #define IO std::ios::sync_with_stdio(0);
  3 #include <bits/stdc++.h>
  4 #define iter ::iterator
  5 using namespace  std;
  6 typedef long long ll;
  7 typedef pair<ll,ll>P;
  8 #define pb push_back
  9 #define se second
 10 #define fi first
 11 #define rs o<<1|1
 12 #define ls o<<1
 13 #define inf 0x3f3f3f3f
 14 const int N=5e5+5;
 15 template <class T>
 16 bool read(T &x){
 17     char c;
 18     bool op = 0;
 19     while(c = getchar(), c < ‘0‘ || c > ‘9‘)
 20         if(c == ‘-‘) op = 1;
 21         else if(c == EOF) return 0;
 22     x = c - ‘0‘;
 23     while(c = getchar(), c >= ‘0‘ && c <= ‘9‘)
 24         x = x * 10 + c - ‘0‘;
 25     if(op) x = -x;
 26     return 1;
 27 }
 28 template <class T>
 29 void write(T x){
 30     if(x < 0) putchar(‘-‘), x = -x;
 31     if(x >= 10) write(x / 10);
 32     putchar(‘0‘ + x % 10);
 33 }
 34 int a[N],c[N];
 35 struct node{
 36     int l,r,id;
 37     bool operator < (const node &t)const{
 38         return r<t.r;
 39     }
 40 }b[N];
 41 int minv[N*4];
 42 void push(int o){
 43     minv[o]=min(minv[ls],minv[rs]);
 44 }
 45 void build(int o,int l,int r){
 46     if(l==r){
 47         minv[o]=inf;
 48         return;
 49     }
 50     int m=(l+r)>>1;
 51     build(ls,l,m);
 52     build(rs,m+1,r);
 53     push(o);
 54 }
 55 void up(int o,int l,int r,int p,int v){
 56     if(l==r){
 57         minv[o]=min(minv[o],v);
 58         return;
 59     }
 60     int m=(l+r)>>1;
 61     if(p<=m)up(ls,l,m,p,v);
 62     else up(rs,m+1,r,p,v);
 63     push(o);
 64 }
 65 int qu(int o,int l,int r,int ql,int qr){
 66     if(l>=ql&&r<=qr){
 67         return minv[o];
 68     }
 69     int m=(l+r)>>1;
 70     int res=inf;
 71     if(ql<=m)res=min(res,qu(ls,l,m,ql,qr));
 72     if(qr>m)res=min(res,qu(rs,m+1,r,ql,qr));
 73     return res;
 74 }
 75 int n,q;
 76 int ans[N],le[N],last[N];
 77 int main(){
 78     read(n);read(q);
 79     for(int i=1;i<=n;i++){
 80         read(c[i]);
 81         a[i]=c[i];
 82     }
 83     sort(c+1,c+1+n);
 84     int n1=unique(c+1,c+1+n)-c-1;
 85     for(int i=1;i<=n;i++){
 86         a[i]=lower_bound(c+1,c+1+n1,a[i])-c;
 87         le[i]=last[a[i]];
 88         last[a[i]]=i;
 89     }
 90     for(int i=1;i<=q;i++){
 91         read(b[i].l);read(b[i].r);
 92         b[i].id=i;
 93     }
 94     sort(b+1,b+1+q);
 95     build(1,1,n);
 96     for(int i=1,j=1;i<=n&&j<=q;i++){
 97         if(le[i]){
 98             up(1,1,n,le[i],i-le[i]);
 99         }
100         while(j<=q&&b[j].r==i){
101             ans[b[j].id]=qu(1,1,n,b[j].l,b[j].r);
102             j++;
103         }
104     }
105     for(int i=1;i<=q;i++){
106         write(ans[i]<inf?ans[i]:-1);
107         putchar(‘\n‘);
108     }
109 }

代码借鉴自胡小兔巨佬

原文地址:https://www.cnblogs.com/ccsu-kid/p/10776839.html

时间: 2024-08-28 14:59:57

51Nod 1571 最近等对(线段树、离线查询)的相关文章

51nod 1463 找朋友(线段树+离线处理)

http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1463 题意: 思路: 好题! 先对所有查询进行离线处理,按照右区间排序,因为k一共最多只有10个,所有在该区间内的B数组,每次枚举K值,通过这样的方式来得到另外一个B值.但是这样得到的B值它在B数组中的位置必须在当前数的左边.如下图:(j为当前数在B数组中的位置,pos为计算得到的另一个B值在数组中的位置) 这两个数的和记录在pos中,这里pos的位置必须在j的左边,假

HDU 4630 No Pain No Game (线段树离线查询)

题目地址:HDU 4630 这题一看数据范围,于是一直在思考n*logn的算法..实在没想到好方法,找了找题解,发现都是用的n*sqrt(n)*logn的方法...算了算,这个复杂度的确可以过..好吧.. 然后就可以先离线下来将询问按r值排序,然后枚举每个数,并且用sqrt(n)的方法枚举所有的约数,然后对于每个约数,对最近的一次出现的这个约数的地方进行更新.因为对于当前区间来讲,只要最近的这个地方更新了,那么前面的查询肯定都能查到这个地方的最大值,所以前面的不用更新. 代码如下: #inclu

HDU 4638 Group (莫队算法||线段树离散查询)

题目地址:HDU 4638 先写了一发莫队,莫队可以水过.很简单的莫队,不多说. 代码如下: #include <iostream> #include <string.h> #include <math.h> #include <queue> #include <algorithm> #include <stdlib.h> #include <map> #include <set> #include <s

Super Mario(线段树离线区间k值)

以前见过这题,没做出来,知道是离线处理,这次仔细想了下, 首先把出现的高度都map离散化一下,以离散化出来的数目g建树,把每个位置都开俩个vector,一个存以这个位置为L的询问,一个存以这个位置为R的询问. 然后从1-g 进行更新,假如当前i是以第j个区间的开始位置,那么这时就可以询问一下<=p[j].h的个数s,显然这时第J个区间多加的,需要减掉,p[j].sum-=s; 然后更新第i个数,update(a[i],1,g,1);再找到某第k区间是以i结尾的,那么依旧询问一下,得出s,p[k]

51nod 1364 最大字典序排列(线段树)

1364 最大字典序排列基准时间限制:1 秒 空间限制:131072 KB 分值: 80 难度:5级算法题 给出一个1至N的排列,允许你做不超过K次操作,每次操作可以将相邻的两个数交换,问能够得到的字典序最大的排列是什么? 例如:N = 5, {1 2 3 4 5},k = 6,在6次交换后,能够得到的字典序最大的排列为{5 3 1 2 4}. Input 第1行:2个数N, K中间用空格分隔(1 <= N <= 100000, 0 <= K <= 10^9). 第2至N + 1行

线段树+离线 hdu5654 xiaoxin and his watermelon candy

传送门:点击打开链接 题意:一个三元组假设满足j=i+1,k=j+1,ai<=aj<=ak,那么就好的.如今告诉你序列.然后Q次询问.每次询问一个区间[l,r],问区间里有多少个三元组满足要求 思路:刚開始看错题目了,原来三元组是连续3个,这作为bc最后一题也太水了把. . . 先一遍预处理.把连续3个满足条件的找出来,放到还有一个数组里排序去重,用这个数组来给三元组哈希.再扫一遍给三元组在之前那个排序好的数组里二分一下得到下标,大概就是哈希一下,用一个数字来表示. 之后的查询.事实上就是.在

gcd(线段树离线处理)——HDU 4630

对应HDU题目:点击打开链接 No Pain No Game Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 1801    Accepted Submission(s): 770 Problem Description Life is a game,and you lose it,so you suicide. But you can

最简单的问题(重庆市第八届大学生程序设计大赛D) (线段树+离线思想)

考场上的时候直接一脸懵逼了,啥? 区间里面又要求子区间,还TM有上下界? 略加思索后倒是发现没有那么麻烦,因为很容易得出如下结论: 1.对于一个满足条件的区间[L , R],对于他所有的子区间显然也满足条件. 2.一个区间[L , R]的子区间数量(包括自己)为(R-L+1)*(R-L+2)/2 证:因为区间都是连续的,所以显然该区间含有R-L+1个长度为1的子区间,R-L个长度为2的子区间,R-L-1个长度为3的子区间......1个长度为R-L+1的子区间 然后根据等差数列求和公式 Sn =

SPOJ--K-query (线段树离线) 离线操作解决一下问题

K-query Given a sequence of n numbers a1, a2, ..., an and a number of k- queries. A k-query is a triple (i, j, k) (1 ≤ i ≤ j ≤ n). For each k-query (i, j, k), you have to return the number of elements greater than k in the subsequence ai, ai+1, ...,

玲珑oj 1117 线段树+离线+离散化,laz大法

1117 - RE:从零开始的异世界生活 Time Limit:1s Memory Limit:256MByte Submissions:438Solved:68 DESCRIPTION 486到了异世界,看到了一群可爱的妹子比如蕾姆啊,艾米莉亚啊,拉姆啊,白鲸啊,怠惰啊等等!有一天膜女告诉486说她的能力可能不能再用了,因为膜女在思考一个数据结构题,没心情管486了.486说我来帮你做,膜女说你很棒棒哦! 给一个集合,最开始为空(不是数学上的集合)五个操作: 1.插入x2.把小于x的数变成x3