标签:
你正在和小冰玩一个猜数字的游戏。小冰首先生成一个长为N的整数序列A1, A2, …, AN。在每一轮游戏中,小冰会给出一个区间范围[L, R],然后你要猜一个数K。如果K在AL, AL+1, …, AR中,那么你获胜。
在尝试了几轮之后,你发现这个游戏太难(无聊)了。小冰决定给你一些提示,你每猜一次,小冰会告诉你K与AL, AL+1, …, AR中最接近的数的绝对差值,即min(|Ai - K|), L ≤ i ≤ R。
现在,请你实现这个新功能。
第一行为一个整数T,表示数据组数。
每组数据的第一行为两个整数N和Q。
第二行为N个由空格分开的整数,分别代表A1, A2, …, AN。
接下来Q行,每行三个由空格隔开的整数L、R、K。
每组数据的先输出一行"Case #X:",X为测试数据编号。
接下来对每个询问输出一行,每行为一个整数,即为所求的值。
1 ≤ T ≤ 20
0 ≤ Ai, K ≤ 109
1 ≤ L ≤ R ≤ N
小数据
1 ≤ N, Q ≤ 1000
大数据
1 ≤ N, Q ≤ 200000
输入数据量较大,推荐使用scanf / BufferedReader等IO方法。
1 9 3 1 8 3 4 9 2 7 6 5 1 9 10 3 7 9 5 6 5
#include <bits/stdc++.h> using namespace std; const int N(2e5+5); int a[19][N], toleft[19][N], sa[N]; void build(int lev, int l, int r){ if(l==r) return; int mid=(l+r)>>1, &tar=sa[mid], nl=mid-l+1; for(int i=l; i<=r; i++) if(a[lev][i]<tar) nl--; for(int i=l, lp=l, rp=mid+1; i<=r; i++){ if(a[lev][i]<tar) a[lev+1][lp++]=a[lev][i]; else if(a[lev][i]>tar) a[lev+1][rp++]=a[lev][i]; else nl?a[lev+1][lp++]=a[lev][i],nl--:a[lev+1][rp++]=a[lev][i]; toleft[lev][i]=toleft[lev][l-1]+lp-l; } build(lev+1, l, mid); build(lev+1, mid+1, r); } //Rank(l, r, k):区间[l, r]内比k小的数的个数 //满足区间加法 int Rank(int lev, int L, int R, int l, int r, int val){ if(L==R) return a[lev][L]<val; int nl=toleft[lev][r]-toleft[lev][l-1], nr=r-l+1-nl, mid=(L+R)>>1; if(sa[mid]>=val){ if(nl){ l=L+toleft[lev][l-1]-toleft[lev][L-1]; r=l+nl-1; return Rank(lev+1, L, mid, l, r, val); } return 0; //error-prone } else{ if(nr){ r+=toleft[lev][R]-toleft[lev][r]; l=r-nr+1; return nl+Rank(lev+1, mid+1, R, l, r, val); } return nl; } } int Query(int lev, int L, int R, int l, int r, int k){ if(L==R) return a[lev][L]; int nl=toleft[lev][r]-toleft[lev][l-1], nr=r-l+1-nl, mid=(L+R)>>1; if(nl>=k){ l=L+toleft[lev][l-1]-toleft[lev][L-1]; r=l+nl-1; return Query(lev+1, L, mid, l, r, k); } r+=toleft[lev][R]-toleft[lev][r]; l=r-nr+1; return Query(lev+1, mid+1, R, l, r, k-nl); } int main(){ int T; scanf("%d", &T); for(int n, q, cs=0; T--;){ scanf("%d%d", &n, &q); printf("Case #%d:\n", ++cs); for(int i=1; i<=n; i++) scanf("%d", sa+i), a[0][i]=sa[i]; sort(sa+1, sa+n+1); build(0, 1, n); for(int l, r, k, rk, res; q--;){ scanf("%d%d%d", &l, &r, &k); rk=Rank(0, 1, n, l, r, k); //printf("%d\n", rk); if(rk==0) res=Query(0, 1, n, l, r, rk+1)-k; else if(rk==r-l+1) res=k-Query(0, 1, n, l, r, rk); else res=min(Query(0, 1, n, l, r, rk+1)-k, k-Query(0, 1, n, l, r, rk)); printf("%d\n", res); } } }
--------------------------------------------------------
问题解决了,但代码不是可以写得再短一些?
Rank和Query可否合并到一起呢?
---------------------------------------------------------
标签:
原文地址:http://www.cnblogs.com/Patt/p/4853401.html