題目鏈接
題意:這題就是先讓你套個公式把n個區間算出來,然後對於單個區間在序列里加上這個區間內所有數,然後再求此時序列的中位數。
題解:中位數實際上就是求整個序列第n/2大,考慮權值線段樹,但是因爲區間範圍太大,所以要對區間進行離散化。
離散化之前,首先要將所有區間的左端點減1。爲什麼呢?因爲離散化後線段樹上的每個點存的實際上是一段區間,那麼比如區間【3,8】,離散化之前我們要把它變成(2,8】,這樣我的3這個點才能代表(2,3】這個區間。
給定兩個區間我們來模擬一下 【3,8】,【5,9】 ,離散化後是這樣子的
2 4 8 9
1 2 3 4
此時(2,8】 對應的是 【1,3】,(4,9】對應的是【2,4】;
還記得我之前說過的嗎,線段樹上每一個點代表的是一段區間。
這個體現在哪裏,體現在對於每一個區間我都會用s[r] - s[l - 1] 來表示,詳情請看代碼。
那麼在線段樹上【1,1】這個點代表的是 s[1] - s[0](0,2】;
【2,2】這個點代表的是s[2] - s[1](2,4】,依次類推下去 3代表的是(4,8】,4代表的是(8,9】。
所以當我要插入【3,8】時,對應的離散化區間不應該是【1,3】,而應該是【1 + 1,3】也就是【2,3】,因爲【2,2】覆蓋了(2,4】,【3,3】覆蓋了(4,8】,所以左端點要往後移一個位置。
這裏離散化之前和之後的區間混在一起可能有點繞,不過我覺得我已經講得很清楚了,如果還有不懂的地方歡迎提問。
#include<bits/stdc++.h>
using namespace std;
#define mid (l + r) / 2
#define ls o * 2
#define rs o * 2 + 1
typedef long long ll;
const int N = 8e5 + 10;
ll sum[N * 4], lazy[N * 4];
ll x[N], y[N], L[N], R[N], s[N];
int n, cnt;
void init()
{
ll a1,b1,c1,m1;
ll a2,b2,c2,m2;
cin>>n;
cin>>x[1]>>x[2]>>a1>>b1>>c1>>m1;
cin>>y[1]>>y[2]>>a2>>b2>>c2>>m2;
for(int i = 1; i <= n; ++i){
if(i > 2){
x[i] = (a1 * x[i - 1] % m1 + b1 * x[i - 2] % m1 + c1 % m1) % m1;
y[i] = (a2 * y[i - 1] % m2 + b2 * y[i - 2] % m2 + c2 % m2) % m2;
}
L[i] = min(x[i], y[i]);//左區間-1
R[i] = max(x[i], y[i]) + 1;
s[++cnt] = L[i];
s[++cnt] = R[i];
}
sort(s + 1, s + 1 + cnt);
cnt = unique(s + 1, s + 1 + cnt) - s - 1;
for(int i = 1; i <= n; ++i){
L[i] = lower_bound(s + 1, s + 1 + cnt, L[i]) - s;
R[i] = lower_bound(s + 1, s + 1 + cnt, R[i]) - s;
}
}
void pu(int o, int l, int r){
if(lazy[o]){
lazy[ls] += lazy[o];
lazy[rs] += lazy[o];
sum[ls] += (s[mid] - s[l - 1]) * lazy[o];
sum[rs] += (s[r] - s[mid]) * lazy[o];
lazy[o] = 0;
}
}
void up(int o, int l, int r, int ql, int qr){
if(ql <= l && qr >= r){
sum[o] += s[r] - s[l - 1];
lazy[o]++;
return;
}
pu(o, l, r);
if(ql <= mid) up(ls, l, mid, ql, qr);
if(qr > mid) up(rs, mid + 1, r, ql, qr);
sum[o] = sum[ls] + sum[rs];
}
ll qu(int o, int l, int r, ll val){
if(l == r){
int tmp = sum[o] / (s[r] - s[l - 1]);//求這段區間內每個數的個數
return (val + tmp - 1) / tmp + s[l - 1];//第一個式子就是向上取整一下
}
pu(o, l, r);
if(val <= sum[ls]) return qu(ls, l, mid, val);//權值線段樹求區間第k大
else return qu(rs, mid + 1, r, val - sum[ls]);
}
int main()
{
init();
for(int i = 1; i <= n; ++i){
up(1, 1, cnt, L[i] + 1, R[i]);//左區間+1
ll v = sum[1]/2 + (sum[1] % 2 == 1);//中位數所在位置
printf("%lld\n", qu(1, 1, cnt, v));
}
}