[UOJR8B]决战圆锥曲线

Posted by Dispwnl on April 12, 2019

题目

题目描述

数学考试,一道圆锥曲线的题难住了你,你开始疯狂地笔算。但是,这题实在太难,于是你决定每种思路多尝试尝试。

你的思维过程可以转化为如下过程:

  • 有一个随机数产生器,有个内部变量 $x$ 初始时为 $x0$,每次产生随机数时它会将 $x$ 变为 $(100000005x+20150609)\bmod 998244353$,然后返回 $⌊\frac{x}{100}⌋$。($a\bmod b$ 表示 $a$ 除以 $b$ 的余数,该运算的优先级高于加减法。$⌊α⌋$ 表示 $α$ 向下取整后的结果。)

  • 初始时有$n$个点,分别编号为$1,…,n$,按编号从小到大顺序生成第$i$个点的坐标:

    • 把横坐标赋为 $i​$。
    • 产生一个随机数 $\hat y$,把纵坐标赋为 $\hat y\bmod 100001$。
  • 有$m​$个操作,表示你的思路过程。操作共有三种:

    • C:按顺序产生随机数 $\hat p,\hat y$,令 $p=\hat p\bmod n+1,y=\hat y\bmod 100001$,然后把第 $p$ 个点的纵坐标修改为 $y$。
    • R:按顺序产生随机数 $\hat p,\hat q​$,令$p=min{\hat p\bmod n+1,\hat q\bmod n+1},q=max{\hat p\bmod n+1,\hat q\bmod n+1}​$,把编号大于等于 $p​$ 小于等于 $q​$ 的点的纵坐标 $y​$ 改为 $100000−y​$。
    • Q $a$ $b$ $c$:查询操作。按顺序产生随机数 $\hat p,\hat q$,令 $p=min{\hat p\bmod n+1,\hat q\bmod n+1},q=max{\hat p\bmod n+1,\hat q\bmod n+1}$,求最小的整数 $t$ 使得:对于所有编号大于等于 $p$ 小于等于 $q$ 的点 $(x,y)$ 都满足 $ax+by+cxy≤t$。($a,b,c$ 均为非负整数)

输入格式

第一行三个整数 $n,m,x0$。保证 $n,m≥1$,$0≤x0<998244353$ 且 $x0≠340787122$。

接下来 $m$ 行,每行表示一个操作,格式如前所述。

输出格式

对于每个查询操作输出一个整数表示最小的 $t$。

样例一

input

3 3 2705443
C
R
Q 872784 195599 7

output

13035048532

explanation

最开始三个点的坐标分别是 $(1,91263),(2,33372),(3,10601)$。

第一个操作把第三个点的坐标改成了 $(3,94317)$。

第二个操作修改了区间 $[2,3]$,第二个点变成了 $(2,66628)$,第三个点变成了 $(3,5683)$。

最后一个操作询问区间 $[2,3]$,可以发现最小的 $t$ 是 $13035048532$。

样例二

见样例数据下载。

限制与约定

所有数据中,对于所有查询操作保证 $0≤a,b<10^6$,$0≤c<40$,保证查询操作的出现次数不超过 $10^5$

测试点编号 $n$的规模 $m$的规模 特殊限制
1 $n≤100$ $m≤100$
2,3 $n≤10^5$ $m≤10^6$ 所有查询操作中 $a=c=0$
4,5 $n≤10^5$ $m≤2×10^5$ 所有查询操作中 $c=0$
6,7 $n≤10^5$ $m≤2×10^5$
8,9,10 $n≤10^5$ $m≤10^6$

时间限制:$2s$

空间限制:$256MB$

题解

数据随机!挺有意思的一道题

测试点$1​$:$O(nm)​$暴力

测试点$2,3​$:直接线段树维护区间$y​$最小值即可

测试点$4,5$:发现要维护区间$ax+by$最小值,可以上凸壳二分求解,因为数据随机,一个区间的凸包的点只有$\log n$个,直接线段树上暴力合并凸包即可,因为有个区间取反操作所以还要维护下凸壳

测试点$6,7$,发现如果$a\le b$并且$y_a\le y_b$,点对$(a,y_a)$就没有贡献了,所以线段树维护一个单调上升序列和单调下降序列,$O(n\log^2 n)$

因为数据随机,上面那个算法只有$\log n$个节点能产生贡献,所以维护区间最大最小$y$值,然后类似$K-D$ $Tree$的查询,先计算右边,更新完再计算左边,叶子节点才可以更新答案

代码

# include<iostream>
# include<cstring>
# include<cstdio>
# include<algorithm>
# define tl (k<<1)
# define tr (k<<1|1)
# define mid (l+r>>1)
# define LL long long
using namespace std;
const int MAX=1e5+5;
struct p{
	int mx,mi;
	bool tags;
}s[MAX<<2];
int n,m,xs;
LL ans;
int a[MAX];
char S[5];
int GO() {return (xs=(100000005ll*xs+20150609)%998244353)/100;}
void GET_REV(int k) {s[k].tags^=1,swap(s[k].mx,s[k].mi),s[k].mx=1e5-s[k].mx,s[k].mi=1e5-s[k].mi;}
void down(int k) {if(s[k].tags) s[k].tags=0,GET_REV(tl),GET_REV(tr);}
void pus(int k) {s[k].mx=max(s[tl].mx,s[tr].mx),s[k].mi=min(s[tl].mi,s[tr].mi);}
void change(int l,int r,int k,int d,int x)
{
	if(l==r) return void(s[k].mx=s[k].mi=d);
	down(k);
	if(x<=mid) change(l,mid,tl,d,x);
	else change(mid+1,r,tr,d,x);
	pus(k);
}
void changed(int l,int r,int k,int L,int R)
{
	if(r<L||R<l) return;
	if(l>=L&&r<=R) return void(GET_REV(k));
	down(k),changed(l,mid,tl,L,R),changed(mid+1,r,tr,L,R),pus(k);
}
LL calc(int x,int y,int a,int b,int c) {return 1ll*x*a+1ll*y*b+1ll*c*x*y;}
void ask(int l,int r,int k,int a,int b,int c,LL &ans)
{
	if(l==r) return void(ans=calc(l,s[k].mx,a,b,c));
	down(k);
	if(calc(r,s[tr].mx,a,b,c)>ans) ask(mid+1,r,tr,a,b,c,ans);
	if(calc(mid,s[tl].mx,a,b,c)>ans) ask(l,mid,tl,a,b,c,ans);
}
void ask(int l,int r,int k,int L,int R,int a,int b,int c,LL &ans)
{
	if(r<L||R<l) return;
	if(l>=L&&r<=R)
	{
		if(calc(r,s[k].mx,a,b,c)>ans) ask(l,r,k,a,b,c,ans);
		return;
	}
	down(k),ask(l,mid,tl,L,R,a,b,c,ans),ask(mid+1,r,tr,L,R,a,b,c,ans);
}
int ask(int l,int r,int k,int x)
{
	if(l==r) return s[k].mx;
	down(k);
	if(x<=mid) return ask(l,mid,tl,x);
	return ask(mid+1,r,tr,x);
}
void build(int l=1,int r=n,int k=1)
{
	if(l==r) return void(s[k].mx=s[k].mi=a[l]);
	build(l,mid,tl),build(mid+1,r,tr),pus(k);
}
int read()
{
	int x(0);
	char ch=getchar();
	for(;!isdigit(ch);ch=getchar());
	for(;isdigit(ch);x=x*10+ch-48,ch=getchar());
	return x;
}
int main()
{
	n=read(),m=read(),xs=read();
	for(int i=1;i<=n;++i)
	  a[i]=GO()%100001;
	build();
	for(int i=1,a,b,c,p,q;i<=m;++i)
	  {
	  	scanf("%s",S);
	  	if(S[0]=='C') change(1,n,1,GO()%100001,GO()%n+1);
	  	else if(S[0]=='R') p=GO()%n+1,q=GO()%n+1,changed(1,n,1,min(p,q),max(p,q));
	  	else if(S[0]=='Q') p=GO()%n+1,q=GO()%n+1,a=read(),b=read(),c=read(),ask(1,n,1,min(p,q),max(p,q),a,b,c,ans=0),printf("%lld\n",ans);
	  }
	return 0;
}