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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值