https://ac.nowcoder.com/acm/contest/887/E
题意:根据所给的条件,先递推的算出n个操作的区间【l,r】,然后按顺序将l,l+1....r加入无限长数组内,然后对于每次求一个中位数,对于偶数的中位数是中间两位靠左的一位
题解:这道题很明显就是离散化线段树的题,只是要处理区间和点的问题,一个离散点代表一个区间,但当加入的是点的话怎么办,本来我打算弄两颗线段树,一颗是点线段树,一颗区间,然后统计的时候,两颗线段树一起贡献,但发现别人的代码贼短,一看才发现,大神们都是一颗线段树就解决的,(处理过程:离散化的时候,把每次的区间右端点加一,这样左端点的离散值就可以表示【l,r+1)的区间了,然后对于单点也会有离散值代表【l,l+1)来表示)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 4e6+9;
struct tt{
ll x1,x2,a,b,c,m;
}a[10];
ll X[maxn],Y[maxn];
ll L[maxn],R[maxn];
ll p[maxn<<2];
ll mp[maxn<<2];
vector<ll>ans;
struct rt{
ll sum,num,lazy;
}dat[maxn<<2];
void pushUp(int k){
dat[k].sum=dat[k<<1].sum+dat[k<<1|1].sum;
// cout<<k<<" ";
// cout<<dat[k].sum<<endl;
}
void pushDown(int k,int l,int r){
int mid=(l+r)>>1;
dat[k<<1].num+=dat[k].lazy;
dat[k<<1].sum+=dat[k].lazy*(mp[mid+1]-mp[l]);
dat[k<<1].lazy+=dat[k].lazy;
dat[k<<1|1].num+=dat[k].lazy;
dat[k<<1|1].sum+=dat[k].lazy*(mp[r+1]-mp[mid+1]);
dat[k<<1|1].lazy+=dat[k].lazy;
dat[k].lazy=0;
}
void updata(int a,int b,int l,int r,int k,ll x){
if(a<=l&&r<=b){
dat[k].num+=x;
dat[k].sum+=x*(mp[r+1]-mp[l]);
dat[k].lazy+=x;
return;
}
if(dat[k].lazy)pushDown(k,l,r);
int mid=(l+r)>>1;
if(a<=mid)updata(a,b,l,mid,k<<1,x);
if(b>mid)updata(a,b,mid+1,r,k<<1|1,x);
pushUp(k);
}
ll query(int l,int r,int k,ll x){
if(l==r){
ll p=x/dat[k].num;
if(x%dat[k].num==0){
return mp[l]+p-1;
}
else{
return mp[l]+p;
}
}
if(dat[k].lazy)pushDown(k,l,r);
int mid=(l+r)>>1;
if(dat[k<<1].sum<x)return query(mid+1,r,k<<1|1,x-dat[k<<1].sum);
else return query(l,mid,k<<1,x);
}
int main(){
int n;
scanf("%d",&n);
for(int i=1;i<=2;i++){
scanf("%lld%lld%lld%lld%lld%lld",&a[i].x1,&a[i].x2,&a[i].a,&a[i].b,&a[i].c,&a[i].m);
}
X[1]=a[1].x1,X[2]=a[1].x2;
Y[1]=a[2].x1,Y[2]=a[2].x2;
for(int i=3;i<=n;i++){
X[i]=(a[1].a*X[i-1]+a[1].b*X[i-2]+a[1].c)%a[1].m;
Y[i]=(a[2].a*Y[i-1]+a[2].b*Y[i-2]+a[2].c)%a[2].m;
}
// for(int i=1;i<=n;i++){
// printf("%lld ",X[i]);
// }
// puts("");
// for(int i=1;i<=n;i++){
// printf("%lld ",Y[i]);
// }
int tot=0;
for(int i=1;i<=n;i++){
L[i]=min(X[i],Y[i])+1;
R[i]=max(X[i],Y[i])+1;
p[tot++]=L[i];
p[tot++]=R[i]+1;
}
sort(p,p+tot);
int num=unique(p,p+tot)-p;
for(int i=1;i<=num;i++){
mp[i]=p[i-1];
}
ll sum=0;
for(int i=1;i<=n;i++){
sum+=R[i]-L[i]+1;
int l1=lower_bound(p,p+num,L[i])-p+1;
int r1=lower_bound(p,p+num,R[i]+1)-p+1;
ll xp=(sum+1)/2;
updata(l1,r1-1,1,num,1,1);
// cout<<dat[1].sum<<"***"<<sum<<endl;
ll k=query(1,num,1,xp);
ans.push_back(k);
}
for(int i=0;i<ans.size();i++){
printf("%lld\n",ans[i]);
}
return 0;
}
/*
10
1 2 3 4 5 6
11 12 13 14 15 16
*/
两颗线段树的写法比较容易想的
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 4e6+9;
struct tt{
ll x1,x2,a,b,c,m;
}a[10];
ll X[maxn],Y[maxn];
ll L[maxn],R[maxn];
ll p[maxn<<2];
ll mp[maxn<<2];
vector<ll>ans;
struct rt{
ll sum,num,lazy,sum2;
}dat[maxn<<2];
void pushUp(int k){
dat[k].sum=dat[k<<1].sum+dat[k<<1|1].sum;
}
void pushUp2(int k){
dat[k].sum2=dat[k<<1].sum2+dat[k<<1|1].sum2;
}
void pushDown(int k,int l,int r){
int mid=(l+r)>>1;
dat[k<<1].num+=dat[k].lazy;
dat[k<<1].sum+=dat[k].lazy*(mp[mid+1]-mp[l]);
dat[k<<1].lazy+=dat[k].lazy;
dat[k<<1|1].num+=dat[k].lazy;
dat[k<<1|1].sum+=dat[k].lazy*(mp[r+1]-mp[mid+1]);
dat[k<<1|1].lazy+=dat[k].lazy;
dat[k].lazy=0;
}
void updata(int a,int b,int l,int r,int k,ll x){
if(a<=l&&r<=b){
dat[k].num+=x;
dat[k].sum+=x*(mp[r+1]-mp[l]);
dat[k].lazy+=x;
return;
}
if(dat[k].lazy)pushDown(k,l,r);
int mid=(l+r)>>1;
if(a<=mid)updata(a,b,l,mid,k<<1,x);
if(b>mid)updata(a,b,mid+1,r,k<<1|1,x);
pushUp(k);
}
void updata_1(int L,int l,int r,int k,int x){
if(l==r){
dat[k].sum2+=x;
return;
}
int mid=(l+r)>>1;
if(L<=mid)updata_1(L,l,mid,k<<1,x);
else updata_1(L,mid+1,r,k<<1|1,x);
pushUp2(k);
}
ll query(int l,int r,int k,ll x){
if(l==r){
if(x<=dat[k].sum2){
return l;
}
x-=dat[k].sum2;
ll p=x/dat[k].num;
if(x%dat[k].num==0){
return mp[l]+p-1;
}
else{
return mp[l]+p;
}
}
if(dat[k].lazy)pushDown(k,l,r);
int mid=(l+r)>>1;
if(dat[k<<1].sum+dat[k<<1].sum2<x)return query(mid+1,r,k<<1|1,x-dat[k<<1].sum-dat[k<<1].sum2);
else return query(l,mid,k<<1,x);
}
int main(){
int n;
scanf("%d",&n);
for(int i=1;i<=2;i++){
scanf("%lld%lld%lld%lld%lld%lld",&a[i].x1,&a[i].x2,&a[i].a,&a[i].b,&a[i].c,&a[i].m);
}
X[1]=a[1].x1,X[2]=a[1].x2;
Y[1]=a[2].x1,Y[2]=a[2].x2;
for(int i=3;i<=n;i++){
X[i]=(a[1].a*X[i-1]+a[1].b*X[i-2]+a[1].c)%a[1].m;
Y[i]=(a[2].a*Y[i-1]+a[2].b*Y[i-2]+a[2].c)%a[2].m;
}
int tot=0;
for(int i=1;i<=n;i++){
L[i]=min(X[i],Y[i])+1;
R[i]=max(X[i],Y[i])+1;
p[tot++]=L[i];
p[tot++]=R[i];
}
sort(p,p+tot);
int num=unique(p,p+tot)-p;
for(int i=1;i<=num;i++){
mp[i]=p[i-1];
}
ll sum=0;
for(int i=1;i<=n;i++){
sum+=R[i]-L[i]+1;
int l1=lower_bound(p,p+num,L[i])-p+1;
int r1=lower_bound(p,p+num,R[i])-p+1;
if(l1==r1){
updata_1(l1,1,num,1,1);
}
else{
updata(l1,r1-1,1,num,1,1);
updata_1(r1,1,num,1,1);
}
ll xp=(sum+1)/2;
// cout<<dat[1].sum+dat[1].sum2<<"***"<<sum<<endl;
ll k=query(1,num,1,xp);
ans.push_back(k);
}
for(int i=0;i<ans.size();i++){
printf("%lld\n",ans[i]);
}
return 0;
}
/*
10
1 2 3 4 5 6
11 12 13 14 15 16
*/