题意:一个初始为空的序列,n次插入,每次插入[L,R]内的所有数字,每次插入后询问中位数。
昨日过掉C后看了一眼E题,一看取模以为是个强制在线的题,再一看数据范围,wdnmd
1
0
9
10^9
109那咋做嘛,就咕咕咕了,结果赛后看了一眼ppt他说离线??然后又看了一眼题,发现这玩意不是强制在线的,然后就顺理成章的秒掉了。
其实还是很好写的,我们维护两个东西,区间内数字出现次数和,以及区间内数字被整体覆盖了多少次。
假设离散化后的数字是:1000,3000,10000,500000。那么线段树底层节点存的是:
[1000,1000],(1000,3000],(3000,10000],(10000,500000]出现的次数,也就是每一个底层节点都存了一个左开右闭的区间内数字的次数。
那么修改操作可以拆成两个操作,一个是单点修改左端点,一个是给区间[L+1,R]内的数字加1。
查询的话,就很像主席树查询第k大那个样子,左子树不行了再去右子树查,当查到底层节点的时候,如果这个节点为1,那么直接返回W[1](离散化后的数组),否则就需要一个小公式来计算了:
当
前
要
查
询
的
次
数
为
x
,
c
i
[
]
为
区
间
数
字
整
体
被
加
的
次
数
,
w
[
l
−
1
]
+
x
/
c
i
[
k
]
+
(
x
m
o
d
c
i
[
k
]
?
1
:
0
)
当前要查询的次数为x,ci[]为区间数字整体被加的次数,w[l-1]+x/ci[k]+(x \mod ci[k]?1:0)
当前要查询的次数为x,ci[]为区间数字整体被加的次数,w[l−1]+x/ci[k]+(xmodci[k]?1:0)
像这种一个点维护一个区间的题还有一道较简单的:CodeForces - 915E
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=4e5+7;
int L[maxn],R[maxn];
int X[maxn],Y[maxn];
int m;
int w[maxn<<1];
void quchong(int n){
sort(w+1,w+1+n);
m=unique(w+1,w+1+n)-w-1;
}
int getid(int x){
return lower_bound(w+1,w+1+m,x)-w;
}
ll lazy[maxn<<3|1];
ll sum[maxn<<3|1];
ll ci[maxn<<3|1];
void build(int l,int r,int k){
lazy[k]=sum[k]=ci[k]=0;
if(l==r) return ;
int mid=(l+r)>>1;
build(l,mid,k<<1);
build(mid+1,r,k<<1|1);
}
void pushup(int k){
sum[k]=sum[k<<1]+sum[k<<1|1];
}
void pushdown(int l,int r,int k){
if(lazy[k]){
lazy[k<<1]+=lazy[k];
lazy[k<<1|1]+=lazy[k];
int mid=(l+r)>>1;
sum[k<<1]+=(w[mid]-w[l-1])*lazy[k];
sum[k<<1|1]+=(w[r]-w[mid])*lazy[k];
ci[k<<1]+=lazy[k];
ci[k<<1|1]+=lazy[k];
lazy[k]=0;
}
}
void updataid(int l,int r,int k,int id,int val){
if(l==r){
sum[k]+=val;
return ;
}
pushdown(l,r,k);
int mid=(l+r)>>1;
if(id<=mid) updataid(l,mid,k<<1,id,val);
else updataid(mid+1,r,k<<1|1,id,val);
pushup(k);
}
void updata(int l,int r,int k,int L,int R,int val){
if(l>=L&&r<=R){
sum[k]+=(w[r]-w[l-1])*1LL*val;
ci[k]++;
lazy[k]+=val;
return ;
}
int mid=(l+r)>>1;
pushdown(l,r,k);
if(L<=mid) updata(l,mid,k<<1,L,R,val);
if(R>mid) updata(mid+1,r,k<<1|1,L,R,val);
pushup(k);
}
ll myfind(int l,int r,int k,ll x){
if(l==r){
if(l==1) return w[l];
if(ci[k]*(w[l]-w[l-1])>=x){
int z=x/ci[k];
int h=x%ci[k];
return w[l-1]+z+(h?1:0);
}
else{
return w[l];
}
}
int mid=(l+r)>>1;
pushdown(l,r,k);
if(sum[k<<1]>=x) return myfind(l,mid,k<<1,x);
return myfind(mid+1,r,k<<1|1,x-sum[k<<1]);
}
int main(){
int n;
int a1,a2,b1,b2,c1,c2,m1,m2;
int id=0;
scanf("%d",&n);
scanf("%d%d%d%d%d%d%d%d%d%d%d%d",&X[1],&X[2],&a1,&b1,&c1,&m1,&Y[1],&Y[2],&a2,&b2,&c2,&m2);
L[1]=min(X[1],Y[1])+1;
R[1]=max(X[1],Y[1])+1;
L[2]=min(X[2],Y[2])+1;
R[2]=max(X[2],Y[2])+1;
w[++id]=L[1];
w[++id]=L[2];
w[++id]=R[1];
w[++id]=R[2];
for(int i=3;i<=n;++i){
X[i]=(1LL*a1*X[i-1]+b1*1LL*X[i-2]+c1)%m1;
Y[i]=(1LL*a2*Y[i-1]+b2*1LL*Y[i-2]+c2)%m2;
L[i]=min(X[i],Y[i])+1;
R[i]=max(X[i],Y[i])+1;
w[++id]=L[i];
w[++id]=R[i];
}
quchong(id);
build(1,m,1);
ll hh=0;
for(int i=1;i<=n;++i){
hh+=R[i]-L[i]+1;
//cout<<L[i]<<" "<<R[i]<<" "<<hh<<endl;
updataid(1,m,1,getid(L[i]),1);
if(L[i]!=R[i])
updata(1,m,1,getid(L[i]+1),getid(R[i]),1);
printf("%lld\n",myfind(1,m,1,(hh+1)/2));
}
return 0;
}
当然还有另一种较为简洁的写法,对于区间直接写作左闭右开区间: [ l , r + 1 ] [l,r+1] [l,r+1],线段树端点维护区间。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=4e5+7;
int L[maxn],R[maxn];
int X[maxn],Y[maxn];
int m;
int w[maxn<<1];
void quchong(int n){
sort(w+1,w+1+n);
m=unique(w+1,w+1+n)-w-1;
}
int getid(int x){
return lower_bound(w+1,w+1+m,x)-w;
}
ll lazy[maxn<<3|1];
ll sum[maxn<<3|1];
void build(int l,int r,int k){
lazy[k]=sum[k]=0;
if(l+1==r) return ;
int mid=(l+r)>>1;
build(l,mid,k<<1);
build(mid,r,k<<1|1);
}
void pushup(int k){
sum[k]=sum[k<<1]+sum[k<<1|1];
}
void pushdown(int l,int r,int k){
if(l+1==r) return ;
if(lazy[k]){
lazy[k<<1]+=lazy[k];
lazy[k<<1|1]+=lazy[k];
int mid=(l+r)>>1;
sum[k<<1]+=(w[mid]-w[l])*lazy[k];
sum[k<<1|1]+=(w[r]-w[mid])*lazy[k];
lazy[k]=0;
}
}
void updata(int l,int r,int k,int L,int R,int val){
if(l>=L&&r<=R){
sum[k]+=(w[r]-w[l])*1LL*val;
lazy[k]+=val;
return ;
}
int mid=(l+r)>>1;
pushdown(l,r,k);
if(R<=mid) updata(l,mid,k<<1,L,R,val);
else if(L>=mid) updata(mid,r,k<<1|1,L,R,val);
else updata(l,mid,k<<1,L,R,val),updata(mid,r,k<<1|1,L,R,val);
pushup(k);
}
ll myfind(int l,int r,int k,ll x){
if(l+1==r){
int len=w[r]-w[l];
ll hh=sum[k]/len;
return w[l]+x/hh-1+(x%hh?1:0);
}
int mid=(l+r)>>1;
pushdown(l,r,k);
if(sum[k<<1]>=x) return myfind(l,mid,k<<1,x);
return myfind(mid,r,k<<1|1,x-sum[k<<1]);
}
int main(){
int n;
int a1,a2,b1,b2,c1,c2,m1,m2;
int id=0;
scanf("%d",&n);
scanf("%d%d%d%d%d%d%d%d%d%d%d%d",&X[1],&X[2],&a1,&b1,&c1,&m1,&Y[1],&Y[2],&a2,&b2,&c2,&m2);
L[1]=min(X[1],Y[1])+1;
R[1]=max(X[1],Y[1])+1;
L[2]=min(X[2],Y[2])+1;
R[2]=max(X[2],Y[2])+1;
++R[1],++R[2];
w[++id]=L[1];
w[++id]=L[2];
w[++id]=R[1];
w[++id]=R[2];
for(int i=3;i<=n;++i){
X[i]=(1LL*a1*X[i-1]+b1*1LL*X[i-2]+c1)%m1;
Y[i]=(1LL*a2*Y[i-1]+b2*1LL*Y[i-2]+c2)%m2;
L[i]=min(X[i],Y[i])+1;
R[i]=max(X[i],Y[i])+1;
++R[i];
w[++id]=L[i];
w[++id]=R[i];
}
quchong(id);
//for(int i=1;i<=m;++i) cout<<w[i]<<" "; cout<<endl;
build(1,m,1);
ll hh=0;
for(int i=1;i<=n;++i){
//cout<<L[i]<<" "<<R[i]<<endl;
hh+=R[i]-L[i];
updata(1,m,1,getid(L[i]),getid(R[i]),1);
printf("%lld\n",myfind(1,m,1,(hh+1)/2));
}
return 0;
}
/*
0 1 2 3 4 5 7 9 10
3 4
3
2 8
4
4 8
5
1 3
4
7 9
5
*/