duliu——思维+线段树

题目

【题目描述】
小 `D` 喜欢出毒瘤题毒人。当然,他的毒瘤更多体现在若干个难题组合在同一场比赛时。
小 `D` 脑中有 $n$ 个毒瘤题 idea,第 $i$ 个的毒值为$d_i$。当第 $i$ 个题和第 $j$ 个题同时出现在一场比赛中,会产生$f(i,j) = d_i + d_j$ 的毒性。
小 `D` 决定用这些题在 YLOJ 上办 $m$ 场在线比赛。
• 由于这个 OJ 还在~~咕咕~~开发,`YLOJ Extremelyhard Round #i` 选取的题目编号集合只能为 $[l_i,r_i]$ 的一个非空子区间 $[a_i,b_i]$。
• 因为这个 round 是 extremelyhard 的,所以需要满足$\sum\limits_{a_i \le j,k \le b_i} f(j,k) \ge x_i$。
• 不过,为了防止题目过分毒瘤而被喷,小 `D` 希望最小化$max_{a_i \le j \le b_i} \{d_i\}$,而你需要告诉他这个最小值。
【输入格式】
从文件 `duliu.in` 中读入数据。
第一行,正整数$n$,自然数$m$。
第二行,$n$ 个正整数,第 $i$ 个元素代表$d_i$。
接下来 $m$ 行,每行三个正整数,分别代表$l_i、r_i、x_i$。
【输出格式】
输出到文件 `duliu.out` 中。
输出 $m$ 行,每行一个整数,代表$min\{max_{a_i \le j \le b_i}\{d_j\}\}$,若没有合法区间,则输出$-1$。
【样例输入一】
5 2
1 1 2 3 4
1 5 2
1 5 11
【样例输出一】
1
2
【样例输入二】
5 4
1 3 2 4 6
1 3 3
1 3 2
2 4 10
1 1 1556528051
【样例输出二】
2
1
3
-1
【数据范围与提示】
保证,$n,m \le 3 \times 10^5,d_i \le 10^7,1 \le l_i \le r_i \le n,x_i \le 10^{18}$。

 题解

毒瘤题目,区间价值和是 $ w=sum*len*2 $,而不是 $ sum*len $,$ j $ 不小于 $ k $

对于以 $ l $ 为起点和以 $ r $ 为结尾的区间,可以直接二分+ RMQ 解决

对于在中间的区间,显然是一个三维偏序,可以整体二分解决

然而本题卡常

记中间的区间为 $ [l_i,r_i] $,和为 $ w_i $

可以发现,当 $ r_i>r $ 时,答案显然没有以 $ r $ 为结尾的区间优,于是就转化为二维偏序,求满足 $ l_i \geq L,w_i \geq x_i $ 的区间中最大值最小

对于一个 $ a_i $,可以预处理出最大值为 $ a_i $ 的区间及它的 $ w_i $

将询问按 $ x_i $,区间按 $ w_i $ 从大到小排序,满足 $ w_i>=x_i $

将 $ a_i $ 记录到以位置为下标的线段树的 $ l_i $ 上,查询的时候只要查询 $ [L,P_r] $ 的最小值即可($ P_r $ 为以 $ r $ 为结尾的区间的左端点)

时间效率:$ O(n \log n) $

代码

 1 #include<bits/stdc++.h>
 2 #define LL long long
 3 #define _(d) while(d(isdigit(ch=getchar())))
 4 using namespace std;
 5 LL R(){
 6     LL x;bool f=1;char ch;_(!)if(ch=='-')f=0;x=ch^48;
 7     _()x=(x<<3)+(x<<1)+(ch^48);return f?x:-x;}
 8 const int N=3e5+5;
 9 int n,m,a[N],st[N][22],lg,tr[N<<2],tot,ans[N];
10 LL sum[N];
11 struct node{int x,id;}s[N];
12 struct pig{int l,r,x;LL w;}p[N],q[N];
13 bool cmp(node a,node b){return a.x>b.x;}
14 bool cmp2(pig a,pig b){return a.w>b.w;}
15 set<int> h;
16 set<int>::iterator it;
17 #define ls rt<<1
18 #define rs rt<<1|1
19 void update(int rt,int l,int r,int x,int v){
20     if(l==r){tr[rt]=min(tr[rt],v);return;}
21     int mid=(l+r)>>1;
22     if(x<=mid)update(ls,l,mid,x,v);
23     else update(rs,mid+1,r,x,v);
24     tr[rt]=min(tr[ls],tr[rs]);
25     return;
26 }
27 int query(int rt,int l,int r,int ql,int qr){
28     if(ql<=l&&qr>=r)return tr[rt];
29     int mid=(l+r)>>1,ans=1e9;
30     if(ql<=mid)ans=query(ls,l,mid,ql,qr);
31     if(qr>mid)ans=min(ans,query(rs,mid+1,r,ql,qr));
32     return ans;
33 }
34 int rmq(int l,int r){
35     int x=log2(r-l+1);
36     return max(st[l][x],st[r-(1<<x)+1][x]);
37 }
38 int main(){
39     n=R(),m=R(),lg=log2(n)+1;
40     for(int i=1;i<=n;i++)
41         sum[i]=(st[i][0]=a[i]=R())+sum[i-1],s[i]=(node){a[i],i};
42     sort(s+1,s+1+n,cmp);
43     h.insert(0),h.insert(n+1);
44     for(int i=1,l,r;i<=n;i++){
45         it=h.lower_bound(s[i].id);
46         r=*it-1,it--,l=*it+1;
47         p[i]=(pig){l,r,s[i].x,(sum[r]-sum[l-1])*(r-l+1)*2};
48         h.insert(s[i].id);
49     }
50     for(int i=1;i<=m;i++){
51         int l=R(),r=R();LL w=R();
52         if((sum[r]-sum[l-1])*(r-l+1)*2<w)ans[i]=-1;
53         else q[++tot]=(pig){l,r,i,w};
54     }
55     sort(p+1,p+1+n,cmp2),sort(q+1,q+1+tot,cmp2);
56     memset(tr,0x3f,sizeof tr);
57     for(int i=1;i<=lg;i++)
58         for(int j=1;j+(1<<i)-1<=n;j++)
59             st[j][i]=max(st[j][i-1],st[j+(1<<(i-1))][i-1]);
60     for(int i=1,j=1;i<=tot;i++){
61         int l=q[i].l,r=q[i].r,res=0;
62         while(l<=r){
63             int mid=(l+r)>>1;
64             if((sum[mid]-sum[q[i].l-1])*(mid-q[i].l+1)*2<q[i].w) l=mid+1;
65             else r=mid-1,res=mid;
66         }
67         ans[q[i].x]=rmq(q[i].l,res);
68         l=q[i].l,r=q[i].r,res=0;
69         while(l<=r){
70             int mid=l+r>>1;
71             if((sum[q[i].r]-sum[mid-1])*(q[i].r-mid+1)*2<q[i].w) r=mid-1;
72             else l=mid+1,res=mid;
73         }
74         ans[q[i].x]=min(ans[q[i].x],rmq(res,q[i].r));
75         while(j<=n&&p[j].w>q[i].w) update(1,1,n,p[j].l,p[j].x),j++;
76         ans[q[i].x]=min(ans[q[i].x],query(1,1,n,q[i].l,res));
77     }
78     for(int i=1;i<=m;i++)printf("%d\n",ans[i]);
79     return 0;
80 }
View Code

 

posted @ 2019-03-23 18:01  Chm_wt  阅读(181)  评论(0编辑  收藏  举报