传送:https://ac.nowcoder.com/acm/contest/887/E
题意:
每次给数组插入区间$[L_i,R_i]$内的所有数,每操作一次查询中位数。
分析:
首先考虑暴力做法。就是对于一个数组,查询中位数的话,需要知道当前数组的大小$sum$,那么中位数的位置就是$(sum-1)/2$。
对于多次插入,多次查询的问题,需要数据结构维护答案。
考虑用线段树维护。线段树维护对于区间$[l,r]$内出现数的个数,同时需要$tag$标记当前区间更新次数。
具体做法:
对于区间$[L_i,R_i]$,首先需要离散化区间,存到$bb$数组再建线段树。这里有一个小技巧,建树的时候将右界扩大1,那么查询的时候长度直接就是$tree[root].r-tree[root].l$。
对于每次的更新区间$[xx,yy]$,标记$tree[root].tag++$,以及$tree[root].num+=(bb[yy]-bb[xx])$。相当于对于每一个线段树的节点,维护了$bb[tree[root].l]--bb[tree[root].r-1]$内数字的个数。这里没有$tree[root].r$的原因是只是为了方便$update$和$query$时计算,这个节点的数字维护在同一级的右半个子树内。
每添加一个区间$[xx,yy]$,插入总数组的数字个数增加了$bb[yy]-bb[xx]$(因为我们的$yy$本身就是$右界+1$了),中位数的位置$res$已经知道,那么在线段树内查询答案。如果左子树的个数$>=res$,就在左子树查询答案;否则就在右子树内查询第$res-tree[root<<1].num$个即可。
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int maxn=4e5+10; 5 struct node{ 6 int l,r;ll num;int tag; 7 }tree[maxn<<3]; 8 int bb[maxn*2],X[maxn],Y[maxn],L[maxn],R[maxn]; 9 void build(int root,int l,int r){ 10 tree[root].l=l;tree[root].r=r; 11 tree[root].num=0; tree[root].tag=0; 12 if (l+1==r) return ; 13 int mid=(l+r)>>1; 14 build(root<<1,l,mid); 15 build(root<<1|1,mid,r); 16 } 17 void pushdown(int root){ 18 if (tree[root].tag==0) return ; 19 if (tree[root].l+1==tree[root].r) return ; 20 tree[root<<1].tag+=tree[root].tag; 21 tree[root<<1].num+=1ll*tree[root].tag*(bb[tree[root<<1].r]-bb[tree[root<<1].l]); 22 tree[root<<1|1].tag+=tree[root].tag; 23 tree[root<<1|1].num+=1ll*tree[root].tag*(bb[tree[root<<1|1].r]-bb[tree[root<<1|1].l]); 24 tree[root].tag=0; 25 } 26 void pushup(int root){ 27 if (tree[root].l+1==tree[root].r) return ; 28 tree[root].num=tree[root<<1].num+tree[root<<1|1].num; 29 } 30 void update(int root,int xx,int yy){ 31 if (xx==tree[root].l && tree[root].r==yy){ 32 tree[root].num+=bb[yy]-bb[xx]; 33 tree[root].tag++; 34 return ; 35 } 36 pushdown(root); 37 int mid=(tree[root].l+tree[root].r)>>1; 38 if (yy<=mid) update(root<<1,xx,yy); 39 else if (xx>=mid) update(root<<1|1,xx,yy); 40 else{ 41 update(root<<1,xx,mid); 42 update(root<<1|1,mid,yy); 43 } 44 pushup(root); 45 } 46 ll query(int root,ll res){ 47 if (tree[root].l+1==tree[root].r){ 48 ll tmp=tree[root].num/(bb[tree[root].r]-bb[tree[root].l]); 49 return bb[tree[root].l]+(res-1)/tmp; 50 } 51 pushdown(root); 52 if (res<=tree[root<<1].num) return query(root<<1,res); 53 else return query(root<<1|1,res-tree[root<<1].num); 54 } 55 int main(){ 56 int n;scanf("%d",&n);int A1,A2,B1,B2,C1,C2,M1,M2; 57 scanf("%d%d%d%d%d%d",&X[1],&X[2],&A1,&B1,&C1,&M1); 58 scanf("%d%d%d%d%d%d",&Y[1],&Y[2],&A2,&B2,&C2,&M2); 59 for (int i=3;i<=n;i++) X[i]=(1ll*A1*X[i-1]+1ll*B1*X[i-2]+C1)%M1; 60 for (int i=3;i<=n;i++) Y[i]=(1ll*A2*Y[i-1]+1ll*B2*Y[i-2]+C2)%M2; 61 int tot=0; 62 for (int i=1;i<=n;i++){ 63 L[i]=min(X[i],Y[i])+1,R[i]=max(X[i],Y[i])+1; R[i]++; 64 bb[++tot]=L[i]; bb[++tot]=R[i]; 65 } 66 sort(bb+1,bb+1+tot); 67 int totn=unique(bb+1,bb+1+tot)-(bb+1); 68 for (int i=1;i<=n;i++){ 69 L[i]=lower_bound(bb+1,bb+1+totn,L[i])-bb; 70 R[i]=lower_bound(bb+1,bb+1+totn,R[i])-bb; 71 } 72 build(1,1,totn); 73 ll sum=0; 74 for (int i=1;i<=n;i++){ 75 update(1,L[i],R[i]); //l--r+1 76 sum+=(bb[R[i]]-bb[L[i]]);// len=r-l+1 77 ll res=(sum+1)/2; 78 ll ans=query(1,res); 79 printf("%lld ",ans); 80 } 81 return 0; 82 }