Scx117
只一眼,便辽阔了时间。

题意:给你一个数列,每次询问左端点在[a,b]中,右端点在[c,d]中的所有子区间的中位数最大值?

n<=1e5.

 

标程:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int read()
 4 {
 5    int x=0,f=1;char ch=getchar();
 6    while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();}
 7    while (ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
 8    return x*f;
 9 }
10 const int N=800005;
11 const int inf=0x3f3f3f3f;
12 int sc,rm[N],lm[N],ls[N],rs[N],rt[N],q[5],n,a[N],b[N],Q,x,l,r,sum[N];
13 void up(int k)
14 {
15     sum[k]=sum[ls[k]]+sum[rs[k]];
16     lm[k]=max(lm[ls[k]],sum[ls[k]]+lm[rs[k]]);
17     rm[k]=max(rm[rs[k]],sum[rs[k]]+rm[ls[k]]);
18 }
19 void build(int &k,int l,int r)
20 {
21     k=++sc;
22    if (l==r) {lm[k]=rm[k]=sum[k]=1;return;}
23    int mid=(l+r)>>1;
24    build(ls[k],l,mid);build(rs[k],mid+1,r);
25    up(k);
26 }
27 void ins(int &k,int pk,int l,int r,int x)
28 {
29    k=++sc;ls[k]=ls[pk];rs[k]=rs[pk];
30     if (l==r) {lm[k]=rm[k]=sum[k]=-1;return;}
31     int mid=(l+r)>>1;
32     if (x<=mid) ins(ls[k],ls[pk],l,mid,x);
33     else ins(rs[k],rs[pk],mid+1,r,x);
34     up(k);
35 }
36 int qry_sum(int k,int l,int r,int L,int R)
37 {
38     if (L>R) return 0;
39     if (L<=l&&r<=R) return sum[k];
40     int mid=(l+r)>>1,res=0;
41     if (L<=mid) res+=qry_sum(ls[k],l,mid,L,R);
42     if (R>mid) res+=qry_sum(rs[k],mid+1,r,L,R);
43     return res;
44 }
45 int qry_lm(int k,int l,int r,int L,int R)
46 {
47     if (L==l&&r==R) return lm[k];
48     int mid=(l+r)>>1;
49     if (L>mid) return qry_lm(rs[k],mid+1,r,L,R);
50     else if (R<=mid) return qry_lm(ls[k],l,mid,L,R);
51     else return max(qry_lm(ls[k],l,mid,L,mid),qry_sum(ls[k],l,mid,L,mid)+qry_lm(rs[k],mid+1,r,mid+1,R));
52 }
53 int qry_rm(int k,int l,int r,int L,int R)
54 {
55     if (L==l&&r==R) return rm[k];
56     int mid=(l+r)>>1;
57     if (L>mid) return qry_rm(rs[k],mid+1,r,L,R);
58     else if (R<=mid) return qry_rm(ls[k],l,mid,L,R);
59     else return max(qry_rm(rs[k],mid+1,r,mid+1,R),qry_sum(rs[k],mid+1,r,mid+1,R)+qry_rm(ls[k],l,mid,L,mid));
60 }
61 bool cmp(int x,int y){return a[x]<a[y];}
62 bool check(int x)
63 {
64     return qry_rm(rt[x],1,n,q[1],q[2])+qry_sum(rt[x],1,n,q[2]+1,q[3]-1)+qry_lm(rt[x],1,n,q[3],q[4])>=0;
65 }
66 int main()
67 {
68     n=read();
69     for (int i=1;i<=n;i++) a[i]=read(),b[i]=i;
70     sort(b+1,b+n+1,cmp);
71    build(rt[1],1,n);
72     for (int i=2;i<=n;i++) ins(rt[i],rt[i-1],1,n,b[i-1]);
73     Q=read();
74     while (Q--)
75     {
76         for (int i=1;i<=4;i++) q[i]=(read()+x)%n+1;
77         sort(q+1,q+5);
78         l=1;r=n;
79         while (l<=r)
80         {
81             int mid=(l+r)>>1;
82             if (check(mid)) x=mid,l=mid+1;else r=mid-1; 
83         }
84         printf("%d\n",x=a[b[x]]);
85     }
86    return 0;
87 }

 

易错点:1.强在,忘了把x更新掉。

2.一开始写的是线段树直接维护前缀和。但是这个区间加等差数列比较麻烦,当然也不是不行。

 

题解:主席树+二分答案

中位数、平均数什么的经典套路就是二分答案。把区间中>=x的设置成1,<x的设置成-1,所以如果有合法区间满足最大区间和>=0,则x可行。

按值依次建立主席树,每次只会增加一条修改为-1的链。(这里不用离散化)

维护前缀最大和后缀最大,还有和。

查询的时候就是前面一段的最大后缀+中间一段的和+后面一段的最大前缀。

posted on 2018-05-23 18:14  Scx117  阅读(176)  评论(0编辑  收藏  举报