2019牛客多校第七场 E Find the median(线段树区间化点)题解
题意:
有一个空的队列,有\(n( n<= 4e5)\)次操作,每次操作会得到一个\(L_i,R_i\),将\(L_i,L_{i+1} \cdots R_{i-1},R_i\)放进队列,每次询问此时队列的中位数。
思路:
因为\(L\)和\(R\)的数量比较少,我们把所有\(L\)和\(R\)的点离散化,如果任意两个点之间还有区间我们就再加一个点表示这个区间,那么我们显然可以得到,每一个点所代表的区间的数量都是相同的,那么只要用线段树维护,然后找区间第\(k\)大即可。最终的点最多为\(4e5 * 2 * 2\),空间花费\(16e5 * 4 * 2 * 8\ byte\),勉强够用。可能有些地方需要优化空间。
代码1:
#include<map>
#include<set>
#include<cmath>
#include<cstdio>
#include<stack>
#include<ctime>
#include<vector>
#include<queue>
#include<cstring>
#include<string>
#include<sstream>
#include<iostream>
#include<algorithm>
#include<unordered_map>
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
const int maxn = 16e5 + 5;
const ll MOD = 998244353;
const ull seed = 131;
const int INF = 0x3f3f3f3f;
struct Node{
int l, r;
}q[maxn];
vector<int> vv, order;
ll num[maxn << 2];
int lazy[maxn << 2];
Node sz[maxn << 2], qujian[maxn];
void pushdown(int rt){
if(lazy[rt]){
num[rt << 1] += lazy[rt] * (sz[rt << 1].r - sz[rt << 1].l + 1LL);
num[rt << 1 | 1] += lazy[rt] * (sz[rt << 1 | 1].r - sz[rt << 1 | 1].l + 1LL);
lazy[rt << 1] += lazy[rt];
lazy[rt << 1 | 1] += lazy[rt];
lazy[rt] = 0;
}
}
void pushup(int rt){
num[rt] = num[rt << 1] + num[rt << 1 | 1];
}
void build(int l, int r, int rt){
num[rt] = lazy[rt] = 0;
if(l == r){
sz[rt] = qujian[l];
return;
}
int m = (l + r) >> 1;
build(l, m, rt << 1);
build(m + 1, r, rt << 1 | 1);
sz[rt].l = sz[rt << 1].l, sz[rt].r = sz[rt << 1 | 1].r;
}
void update(int L, int R, int l, int r, int rt){
if(L <= l && R >= r){
lazy[rt]++;
num[rt] += (sz[rt].r - sz[rt].l + 1LL);
return;
}
pushdown(rt);
int m = (l + r) >> 1;
if(L <= m)
update(L, R, l, m, rt << 1);
if(R > m)
update(L, R, m + 1, r, rt << 1 | 1);
pushup(rt);
}
int queryK(int l, int r, ll k, int rt){
if(l == r){
int pos = k / lazy[rt];
return k % lazy[rt] == 0? sz[rt].l + pos - 1 : sz[rt].l + pos;
}
pushdown(rt);
int m = (l + r) >> 1;
ll Lnum = num[rt << 1];
if(Lnum >= k)
return queryK(l, m, k, rt << 1);
else
return queryK(m + 1, r, k - Lnum, rt << 1 | 1);
}
int x[maxn / 2], y[maxn / 2];
int main(){
// freopen("1.txt", "w", stdout);
int n;
ll a1, b1, c1, m1, a2, b2, c2, m2;
vv.clear();
order.clear();
scanf("%d", &n);
scanf("%lld%lld%lld%lld%lld%lld", &x[1], &x[2], &a1, &b1, &c1, &m1);
scanf("%lld%lld%lld%lld%lld%lld", &y[1], &y[2], &a2, &b2, &c2, &m2);
for(int i = 1; i <= n; i++){
if(i > 2){
x[i] = (a1 * x[i - 1] + b1 * x[i - 2] + c1) % m1;
y[i] = (a2 * y[i - 1] + b2 * y[i - 2] + c2) % m2;
}
q[i].l = min(x[i], y[i]) + 1;
q[i].r = max(x[i], y[i]) + 1;
vv.push_back(q[i].l), vv.push_back(q[i].r);
}
sort(vv.begin(), vv.end());
vv.erase(unique(vv.begin(), vv.end()), vv.end());
int cnt = 0;
for(int i = 0; i < vv.size(); i++){ //线段树区间规划
qujian[++cnt].l = vv[i], qujian[cnt].r = vv[i];
order.push_back(vv[i]);
if(i + 1 < vv.size() && vv[i + 1] - vv[i] > 1){
qujian[++cnt].l = vv[i] + 1, qujian[cnt].r = vv[i + 1] - 1;
order.push_back(vv[i] + 1);
}
}
build(1, cnt, 1);
int l, r;
ll sum = 0;
for(int i = 1; i <= n; i++){
l = lower_bound(order.begin(), order.end(), q[i].l) - order.begin() + 1;
r = lower_bound(order.begin(), order.end(), q[i].r) - order.begin() + 1;
update(l, r, 1, cnt, 1);
sum += q[i].r - q[i].l + 1;
printf("%d\n", queryK(1, cnt, (sum + 1) / 2, 1));
}
return 0;
}