本质上是一个离散化的权值线段树,其实很简单,比赛时候没写出来是个遗憾,主要当时没考虑清楚离散化的对象,结果和之后的处理方式。
刚开始看题面里一个数据生成公式,以为是强制在线的,后来发现其实是假的,输入是可以全部离线处理出来的。这样的话就可以先把每一步中的L,R求出来了。之后的话,注意到题目的操作实质上相当于权值线段树的操作就可以计数了,我这里当时以为是add值的操作,其实只是增加了数字的个数而已。但是数字范围会很大,所以要离散化一下。这里要特别注意的是在这种区间的离散化之后,就不是原来线段树了(原来的我们所谓正常的线段树其实相当于是个点树),因此要用[l,r)这种左闭右开的区间来计算,否则二分的时候会漏掉中间的一段[mid,mid+1]。
wa点的话有一个是查询的时候参考值要用long long,因为他最大可能是4e5*1e9的,另一个是要开8倍空间,因为4e5个操作其实有8e5个l(r)值。。。
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 400010;
ll X[maxn],Y[maxn],lrsa[maxn][2],lrs[maxn<<1];
ll L[maxn],R[maxn];
struct node{
int l,r;
ll sum,lazy;
}tree[maxn<<3];//<<2 or << 3?
void build(int o,int l,int r){
tree[o].l=l,tree[o].r=r;
tree[o].sum=tree[o].lazy=0;
if(l+1==r) return ;
build(o<<1,l,(l+r)>>1);
build(o<<1|1,(l+r)>>1,r);
}
void pushdown(int o){
if(tree[o].l+1==tree[o].r||tree[o].lazy==0) return ;
else{
tree[o<<1].lazy+=tree[o].lazy;
tree[o<<1|1].lazy+=tree[o].lazy;
tree[o<<1].sum+=tree[o].lazy*(lrs[tree[o<<1].r]-lrs[tree[o<<1].l]);
tree[o<<1|1].sum+=tree[o].lazy*(lrs[tree[o<<1|1].r]-lrs[tree[o<<1|1].l]);//error2 o<1????
tree[o].lazy=0;
}
}
void maintain(int o){
if(tree[o].l+1==tree[o].r) return ;
tree[o].sum=tree[o<<1].sum+tree[o<<1|1].sum;
}
int ql,qr;
void update(int o,int l,int r){
if(ql<=l&&r<=qr){
tree[o].lazy+=1;
tree[o].sum+=lrs[r]-lrs[l];
}
else{
int mid=(l+r)>>1;
pushdown(o);
if(ql<mid) update(o<<1,l,mid);
if(mid<qr) update(o<<1|1,mid,r);
maintain(o);
}
}
int query(int o,ll v){//error3 long long v!
if(tree[o].l+1==tree[o].r){
ll unit=tree[o].sum/(lrs[tree[o].r]-lrs[tree[o].l]);//error1 lrs
return (int)(lrs[tree[o].l]+ceil(1.0*v/unit)-1);
}
else{
pushdown(o);
if(v<=tree[o<<1].sum) return query(o<<1,v);
else return query(o<<1|1,v-tree[o<<1].sum);
}
}
void solve(int n){
int tot=0;
for(int i=1;i<=n;i++){
lrsa[i][1]++;//[l,r]->[l,r+1)
lrs[tot++]=lrsa[i][0];
lrs[tot++]=lrsa[i][1];
}
sort(lrs,lrs+tot);
tot=unique(lrs,lrs+tot)-lrs;
for(int i=1;i<=n;i++){
L[i]=lower_bound(lrs,lrs+tot,lrsa[i][0])-lrs;
R[i]=lower_bound(lrs,lrs+tot,lrsa[i][1])-lrs;
}
build(1,0,tot-1);
ll tp=0;
for(int i=1;i<=n;i++){
tp+=lrsa[i][1]-lrsa[i][0];
ql=L[i],qr=R[i];
update(1,0,tot-1);
printf("%d\n",query(1,(tp+1)>>1));
}
}
int main() {
int n;
while(scanf("%d",&n)==1){
ll A,B,C,M;
scanf("%lld%lld%lld%lld%lld%lld",&X[1],&X[2],&A,&B,&C,&M);
for(int i=3;i<=n;i++){
X[i]=(A*X[i-1]+B*X[i-2]+C)%M;
}
scanf("%lld%lld%lld%lld%lld%lld",&Y[1],&Y[2],&A,&B,&C,&M);
for(int i=3;i<=n;i++){
Y[i]=(A*Y[i-1]+B*Y[i-2]+C)%M;
}
for(int i=1;i<=n;i++){
lrsa[i][0]=1+min(X[i],Y[i]);
lrsa[i][1]=1+max(X[i],Y[i]);
}
solve(n);
}
return 0;
}
