2019牛客多校第七场 E.Find the median

传送: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\n",ans);
80     }
81     return 0;
82 }

 

posted @ 2019-08-09 15:12  Changer-qyz  阅读(496)  评论(0编辑  收藏  举报