做的第一道整体二分题。
整体二分的套路:
二分一个答案,对于每个询问求出答案,再把询问分成两部分,第一个部分是答案< mid的,第二个部分是答案大于mid的,至于=mid的,这个询问不一定是mid,先把答案记一下,根据实际情况而决定分到哪个部分。
这题首先得把[x, y]的限制具体化,用一棵主席树预处理[x..y]限制对应的a值是什么。
二分一个答案mid,把b值小于等于mid的元素加入坐标系,横坐标是a值,纵坐标是序号。
对于每个询问,相当于询问[l..r][x_..y_]的点数(x_、y_是x,y具体化以后的a值大小),这个可以拆开,排个序,用个扫描线加树状数组的东西维护一下就可以了。
求出答案,需要把询问分到它们应该去的部分,s>=mid,则说明答案<=mid,s
#include
#include
#include
#define low(x) ((x) & -(x))
#define fo(i, x, y) for(int i = x; i <= y; i ++)
using namespace std;
const int N = 100005;
int n, m;
struct node {
int fi, se, num;
}a[N];
struct tree {
int l, r, s;
}t[N * 100];
int g[N], tp;
int opl, opr, opx;
struct Ask {
int l, r, x, y, k, to, ans, s;
}b[N];
int xg(int i, int l, int r) {
if(l > opl || r < opl) return i;
if(l == r) {
t[++ tp] = t[i]; t[tp].s ++;
return tp;
}
int m = l + r >> 1; t[++ tp] = t[i]; i = tp;
t[i].l = xg(t[i].l, l, m); t[i].r = xg(t[i].r, m + 1, r);
t[i].s = t[t[i].l].s + t[t[i].r].s;
return i;
}
int query(int g1, int g2, int l, int r, int v) {
if(l == r) return l;
int m = l + r >> 1, l1 = t[g1].l, l2 = t[g2].l;
if(t[l2].s - t[l1].s >= v)
return query(t[g1].l, t[g2].l, l, m, v); else
return query(t[g1].r, t[g2].r, m + 1, r, v - (t[l2].s - t[l1].s));
}
void Init() {
scanf("%d", &n);
fo(i, 1, n) scanf("%d", &a[i].fi);
fo(i, 1, n) scanf("%d", &a[i].se);
g[0] = tp = 1;
fo(i, 1, n) {
opl = a[i].fi;
g[i] = xg(g[i - 1], 1, n);
}
scanf("%d", &m);
fo(i, 1, m) {
scanf("%d %d %d %d %d", &b[i].l, &b[i].r, &b[i].x, &b[i].y, &b[i].k);
b[i].x = query(g[b[i].l - 1], g[b[i].r], 1, n, b[i].x);
b[i].y = query(g[b[i].l - 1], g[b[i].r], 1, n, b[i].y);
}
}
struct node2 {
int h, x, y, f, to;
}c[N * 2];
bool rank_c(node2 a, node2 b) {
return a.h < b.h;
}
struct node3 {
int h, w;
}d[N];
bool rank_d(node3 a, node3 b) {
return a.h < b.h;
}
int f[N];
void add(int x, int y) {
while(x <= n) {
f[x] += y;
x += low(x);
}
}
int find(int x) {
int s = 0;
while(x) {
s += f[x];
x -= low(x);
}
return s;
}
bool rank_b(Ask a, Ask b) {
if(a.s < a.k && b.s >= b.k) return 0;
if(a.s > a.k && b.s <= b.k) return 1;
if(a.s == a.k) {
if(b.s < b.k) return 1;
if(b.s > b.k) return 0;
}
return 0;
}
void EF(int x, int y, int ax, int ay, int bx, int by) {
if(x > y) return;
if(ax > ay) return;
if(bx > by) return;
int mid = (x + y) / 2;
int tc = 0;
fo(i, bx, by) {
b[i].s = 0;
c[++ tc].f = -1;
c[tc]. h = b[i].l - 1;
c[tc].x = b[i].x; c[tc].y = b[i].y;
c[tc].to = i;
c[++ tc].f = 1;
c[tc]. h = b[i].r;
c[tc].x = b[i].x; c[tc].y = b[i].y;
c[tc].to = i;
}
sort(c + 1, c + tc + 1, rank_c);
int neway = ay;
while(neway >= ax && a[neway].se > mid) neway --; //find neway
int td = 0;
fo(i, ax, neway) d[++ td].h = a[i].num, d[td].w = a[i].fi;
sort(d + 1, d + td + 1, rank_d);
int dz = 0;
fo(i, 1, tc) {
while(dz < td && d[dz + 1].h <= c[i].h) dz ++, add(d[dz].w, 1);
b[c[i].to].s += c[i].f * (find(c[i].y) - find(c[i].x - 1));
}
while(dz) add(d[dz].w, -1), dz --; //clear f
sort(b + bx, b + by + 1, rank_b);
fo(i, bx, by) if(b[i].s == b[i].k) b[i].ans = mid;
int newby = by;
while(newby >= bx && b[newby].s < b[newby].k) newby --;
int newbx = bx;
while(newbx <= by && b[newbx].s >= b[newbx].k) newbx ++;
fo(i, newbx, by) b[i].k -= b[i].s;
EF(x, mid - 1, ax, neway, bx, newby);
EF(mid + 1, y, neway + 1, ay, newbx, by);
}
bool rank_a(node a, node b) {
return a.se < b.se;
}
int ans[N];
int main() {
freopen("sequence.in", "r", stdin);
freopen("sequence.out", "w", stdout);
Init();
fo(i, 1, n) a[i].num = i;
sort(a + 1, a + n + 1, rank_a);
fo(i, 1, m) b[i].to = i;
EF(1, n, 1, n, 1, m);
fo(i, 1, m) ans[b[i].to] = b[i].ans;
fo(i, 1, m) printf("%d\n", ans[i]);
}