2019牛客暑期多校训练营(第七场)E-Find the median
离线+树状数组+二分
首先记录下所有的位置,Li和Ri,做离线处理(首先需要离散化)。
对于每一个时刻,我们进行插入和查询的操作。做权值树状数组。
在Li位置+1,Ri位置-1,使得离散化后的两个端点,区间更新,然而问题出现在,我们如何进行查询。
我们可以知道,中间的那个数字,其实就是以他为端点的左区间,权值和小于n/2,所以二分一个中值出来,查询中值的左区间,看看是否满足条件。
那么我们离散化了区间,比如3-7,应该是3,4,5,6,7,都加上1,然而我们离散化后,只有3,7加了1,无法统计,所以就再开一个数组,记录每一次加和的区间长度,那么针对查询例如6,我们就可以这样计算,6*左边的权值加上区间长度。
为了方便,我们这里记Ri=Ri+1,把区间变成[Li,Ri),这样,每一次二分查询的时候,例如7,我们更新过3-7这个区间,那么这个时候他的左端点就有3和7两个,而我们往右更新的时候,7这个端点加上了区间长度,那么答案计算就是错误的所以这么做为了方便,如果不加的话,那么做[Li,Ri]区间的更新时候,累加的区间长度需要从下一个区间开始加入。
#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
//#include<regex>
#include<cstdio>
#define up(i,a,b) for(int i=a;i<b;i++)
#define dw(i,a,b) for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
int read()
{
char ch = getchar(); int x = 0, f = 1;
while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
return x * f;
}
typedef pair<int, int> pir;
//struct mat { ll a[2][2]; };
//mat mat_mul(mat x, mat y,ll modd)
//{
// mat res;
// memset(res.a, 0, sizeof(res.a));
// upd(i, 0, 1)
// {
// upd(k, 0, 1)
// {
// if (!x.a[i][k])continue;//一定要是i,k才能优化
// upd(j, 0, 1)
// {
// res.a[i][j] = (res.a[i][j]+ x.a[i][k] * y.a[k][j]%modd)%modd;
// }
// }
// }
// return res;
//}
//mat mat_pow(int k, mat mod,ll modd)
//{
// mat res;
// memset(res.a, 0, sizeof(res.a));
// upd(i, 0, 1)
// res.a[i][i] = 1;
// while (k > 0)
// {
// if (k & 1)res = mat_mul(res, mod,modd);
// mod = mat_mul(mod, mod,modd);
// k >>= 1;
// }
// return res;
//}
int N;
vector<ll>Xi;
vector<ll>Yi;
vector<ll>ls;
ll sum[400005 * 4];
ll sum2[400005 * 4];
ll x1, x2, a1, b1, c1, m1, y11, y2, a2, b2, c2, m2;
int lowbit(int i)
{
return i & (-i);
}
void update(ll pos, ll val, ll len)
{
while (pos <= ls.size())
{
sum[pos] += val;
sum2[pos] += len;
pos += lowbit(pos);
}
}
ll querry(ll mid)
{
ll ve1 = 0, ve2 = 0;
ll ps = upper_bound(ls.begin(), ls.end(), mid) - ls.begin();
if (ps == ls.end() - ls.begin()+1)return 1e9 + 5;
while (ps)
{
ve1 += sum[ps];
ve2 += sum2[ps];
ps -= lowbit(ps);
}
return ve1 * (mid)+ve2;
}
int main()
{
N = read();
cin >> x1 >> x2 >> a1 >> b1 >> c1 >> m1;
cin >> y11 >> y2 >> a2 >> b2 >> c2 >> m2;
Xi.push_back(x1); Xi.push_back(x2);
Yi.push_back(y11); Yi.push_back(y2);
up(i, 2, N)
{
ll xi = (a1*Xi[i - 1] % m1 + b1 * Xi[i - 2] % m1 + c1) % m1;
ll yi = (a2*Yi[i - 1] % m2 + b2 * Yi[i - 2] % m2 + c2) % m2;
Xi.push_back(xi);
Yi.push_back(yi);
}
up(i, 0, N)
{
int temp = max(Xi[i], Yi[i]);
int tempmin = min(Xi[i], Yi[i]);
temp++, tempmin++;
Xi[i] = tempmin, Yi[i] = temp;
ls.push_back(temp+1);
ls.push_back(tempmin);
}
sort(ls.begin(), ls.end());
ls.erase(unique(ls.begin(), ls.end()), ls.end());
ll sum = 0;
up(i, 0, N)
{
int pos1 = lower_bound(ls.begin(), ls.end(), Xi[i]) - ls.begin();
int pos2 = lower_bound(ls.begin(), ls.end(), Yi[i]+1) - ls.begin();
pos1++; pos2++;
sum += Yi[i] - Xi[i] + 1;
update(pos1, 1, -Xi[i]);
update(pos2, -1, (Yi[i] + 1));
ll aim;
if (sum & 1)aim = sum / 2;
else aim = sum / 2 - 1;
ll lf = 0; ll rt = 1e9+5;
while (rt > lf + 1)
{
ll mid = (rt + lf) >> 1;
if (aim < querry(mid))
{
rt = mid;
}
else
lf = mid;
}
cout << lf << endl;
}
return 0;
}
橙橙橙