zoukankan      html  css  js  c++  java
  • Codeforces Round #765 Div.1 F. Souvenirs 线段树

    题目链接:http://codeforces.com/contest/765/problem/F

    题意概述:

    给出一个序列,若干组询问,问给出下标区间中两数作差的最小绝对值。

    分析:

    这个题揭示着数据结构题目世界的真谛......

    在线显然凉凉......考虑离线做法。

    本题的主要思想:

      首先考虑把所有的询问按照右端点排序,用一个指针扫整个序列,同时考虑i作为一组差的右端可以对右端点大于等于i的询问做出的贡献。我们可以发现,我们扫到当前点i,对于所有询问的右端点大于等于i的询问,如果其左端点小于等于i,那么i这个位置就可能对它们的答案做出贡献,换句话说我们只要考虑i作为差的右端可以对哪些左端的答案做出贡献,然后维护当前每个点作为左端的答案,查询的时候直接进行区间最小值的查询即可。

      绝对值是麻烦的,因此我们简单一点,考虑所有j<i并且aj>=ai的贡献,然后倒着扫一遍就可以考虑剩下的可能贡献。

      假设我们现在扫到位置i,左边有第一个大于ai的元素aj,我们贪心考虑,最终能够让 i作为下标较大的一方参与的答案变得更小 的j'满足:ai<=aj'<aj。但是这个性质显然还不够强,我们继续考虑,发现:

      当aj'-ai>aj-aj'时,我们反向扫回来的时候,由于区间[j',j]一定被[j',i]包含,如果存在一个询问包括了[j',i],那么也一定包括了[j',j],显然这个时候aj-aj'是一个更加优秀的答案,aj'-ai更劣。

      因此我们找到的j'一定要满足:aj'-ai<=aj-aj' -> 2aj'<=ai+aj,也就是说我们最多找到O(log(ai+a_first_j))个可以对i作为右端点的答案产生贡献的位置。

      因为我们将右端点排序,因此我们维护当前所有的点作为下标较小的一方参与的时候的答案,当我们遇到一个询问p的右端点pr=i的时候,只需要查询区间[pl,i]中的最小值即可。

      最后倒着来一遍,得到最终的答案。

      在log次查找的时候我们实质上找的是权值在[ai,(ai+aj)/2]范围中的小于j的最大下标,分析一下发现可以直接用一棵权值线段树维护,因为我们找的权值区间内的序列下标不可能大于j(不然的话我们在之前就应该找到它了)。

      找到第一个j的时候可以直接在序列线段树中进行二分。

      时间复杂度O(NlogNloga)

      (PS:突然发现变量rank,hash在C++11下面编译不了是什么情况?!)

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<cstdlib>
      5 #include<algorithm>
      6 #include<cmath>
      7 #include<queue>
      8 #include<set>
      9 #include<map>
     10 #include<vector>
     11 #include<cctype>
     12 #define inf (1e9+5)
     13 using namespace std;
     14 const int MAXN=100005;
     15 const int MAXM=300005;
     16 
     17 int N,M,A[MAXN],Rank[MAXN],B[MAXN],ans[MAXM],tot;
     18 struct data{
     19     int l,r,id;
     20     friend bool operator < (data x,data y){
     21         return x.r<y.r;
     22     }
     23 }q[MAXM];
     24 struct segment_tree{
     25     static const int maxn=200005;
     26     int rt,np,lc[maxn],rc[maxn],mx[maxn],mn[maxn];
     27     void init(){ rt=np=0; }
     28     void pushup1(int now){ mn[now]=min(mn[lc[now]],mn[rc[now]]); }
     29     void pushup2(int now){ mx[now]=max(mx[lc[now]],mx[rc[now]]); }
     30     void build(int &now,int L,int R){
     31         now=++np,lc[now]=rc[now]=0,mx[now]=-1,mn[now]=inf;
     32         if(L==R) return;
     33         int m=L+R>>1;
     34         build(lc[now],L,m);
     35         build(rc[now],m+1,R);
     36     }
     37     void update1(int now,int L,int R,int pos,int v){
     38         if(L==R){ mn[now]=min(mn[now],v); return; }
     39         int m=L+R>>1;
     40         if(pos<=m) update1(lc[now],L,m,pos,v);
     41         else update1(rc[now],m+1,R,pos,v);
     42         pushup1(now);
     43     }
     44     void update2(int now,int L,int R,int pos,int v){
     45         if(L==R){ mx[now]=max(mx[now],v); return; }
     46         int m=L+R>>1;
     47         if(pos<=m) update2(lc[now],L,m,pos,v);
     48         else update2(rc[now],m+1,R,pos,v);
     49         pushup2(now);
     50     }
     51     int query_p(int now,int L,int R,int v){
     52         if(L==R) return mx[now]>=v?L:-1;
     53         int m=L+R>>1;
     54         if(mx[rc[now]]>=v) return query_p(rc[now],m+1,R,v);
     55         return query_p(lc[now],L,m,v);
     56     }
     57     int query_max(int now,int L,int R,int A,int B){
     58         if(A<=L&&R<=B) return mx[now];
     59         int m=L+R>>1;
     60         if(B<=m) return query_max(lc[now],L,m,A,B);
     61         if(A>m) return query_max(rc[now],m+1,R,A,B);
     62         return max(query_max(lc[now],L,m,A,B),query_max(rc[now],m+1,R,A,B));
     63     }
     64     int query_min(int now,int L,int R,int A,int B){
     65         if(A<=L&&R<=B) return mn[now];
     66         int m=L+R>>1;
     67         if(B<=m) return query_min(lc[now],L,m,A,B);
     68         if(A>m) return query_min(rc[now],m+1,R,A,B);
     69         return min(query_min(lc[now],L,m,A,B),query_min(rc[now],m+1,R,A,B));
     70     }
     71 }st1,st2;
     72 
     73 void data_in()
     74 {
     75     scanf("%d",&N);
     76     for(int i=1;i<=N;i++) scanf("%d",&A[i]);
     77     scanf("%d",&M);
     78     for(int i=1;i<=M;i++){
     79         scanf("%d%d",&q[i].l,&q[i].r);
     80         q[i].id=i;
     81     }
     82 }
     83 int id(int v){ return upper_bound(B+1,B+tot+1,v)-B-1; }
     84 void solve()
     85 {
     86     st1.init(); st2.init();
     87     st1.build(st1.rt,1,N); st2.build(st2.rt,1,tot);
     88     int p=1;
     89     st1.update2(st1.rt,1,N,1,A[1]);
     90     st2.update2(st2.rt,1,tot,Rank[1],1);
     91     for(int i=2;i<=N;i++){
     92         int j=st1.query_p(st1.rt,1,N,A[i]);
     93         if(j!=-1){
     94             st1.update1(st1.rt,1,N,j,A[j]-A[i]);
     95             while((j=st2.query_max(st2.rt,1,tot,Rank[i],id((A[i]+A[j])/2)))!=-1){
     96                 st1.update1(st1.rt,1,N,j,A[j]-A[i]);
     97                 if(A[j]-A[i]==0) break;
     98             }
     99         }
    100         while(p<=M&&q[p].r<=i){
    101             ans[q[p].id]=min(ans[q[p].id],st1.query_min(st1.rt,1,N,q[p].l,q[p].r));
    102             p++;
    103         }
    104         if(p>M) break;
    105         st1.update2(st1.rt,1,N,i,A[i]);
    106         st2.update2(st2.rt,1,tot,Rank[i],i);
    107     }
    108 }
    109 void work()
    110 {
    111     memcpy(B,A,sizeof(A));
    112     sort(B+1,B+N+1);
    113     tot=unique(B+1,B+N+1)-B-1;
    114     
    115     for(int i=1;i<=N;i++) Rank[i]=lower_bound(B+1,B+tot+1,A[i])-B;
    116     for(int i=1;i<=M;i++) ans[i]=inf;
    117     sort(q+1,q+M+1);
    118     solve();
    119     
    120     int l=1,r=N;
    121     while(l<r) swap(Rank[l],Rank[r]),swap(A[l++],A[r--]);
    122     for(int i=1;i<=M;i++){
    123         swap(q[i].l,q[i].r);
    124         q[i].l=N-q[i].l+1,q[i].r=N-q[i].r+1;
    125     }
    126     sort(q+1,q+M+1);
    127     solve();
    128     
    129     for(int i=1;i<=M;i++) printf("%d
    ",ans);
    130 }
    131 int main()
    132 {
    133     data_in();
    134     work();
    135     return 0;
    136 }
    View Code
  • 相关阅读:
    video 自动循环播放
    C. Kefa and Park
    B. Random Teams(数学题)
    B. Books(水题)
    dd爱科学1.0(牛客)
    B. WeirdSort
    B. The Cake Is a Lie
    优先队列 priority_queue
    C. A-B Palindrome
    B. Fedor and New Game(位运算)
  • 原文地址:https://www.cnblogs.com/KKKorange/p/8763203.html
Copyright © 2011-2022 走看看