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
*/