zoukankan      html  css  js  c++  java
  • BZOJ 4408 FJOI2016 神秘数 可持久化线段树

    Description

    一个可重复数字集合S的神秘数定义为最小的不能被S的子集的和表示的正整数。例如S={1,1,1,4,13},
    1 = 1
    2 = 1+1
    3 = 1+1+1
    4 = 4
    5 = 4+1
    6 = 4+1+1
    7 = 4+1+1+1
    8无法表示为集合S的子集的和,故集合S的神秘数为8。
    现给定n个正整数a[1]..a[n],m个询问,每次询问给定一个区间[l,r](l<=r),求由a[l],a[l+1],…,a[r]所构成的可重复数字集合的神秘数。

    Input

    第一行一个整数n,表示数字个数。
    第二行n个整数,从1编号。
    第三行一个整数m,表示询问个数。
    以下m行,每行一对整数l,r,表示一个询问。

    Output

    对于每个询问,输出一行对应的答案。

    Sample Input

    5
    1 2 4 9 10
    5
    1 1
    1 2
    1 3
    1 4
    1 5

    Sample Output

    2
    4
    8
    8
    8

    HINT

    对于100%的数据点,n,m <= 100000,∑a[i] <= 10^9

    题意极为简洁。。。。

    可以发现这个题需要分析一些性质来判断一个数是否可以被凑出来。一个数被凑出来的时候一定不会用到大于它的数字,只可能会用到小于它的数字。

    问题看起来很无序,那么找到一个考虑的顺序,把询问区间内所有的数字从小到大开始考虑。首先看有没有1,如果有,那么1就可以凑出来,同时可以发现如果有x个1,那么1~x都可以凑出来。那么考虑1~x范围内的所有数字,你可发现任何一个非1的数字都可以使我们可以连续表达的数字区间增大了(脑补一个移动的窗口),1~x区间内能表示出的最大数字就是 x+(区间内小于等于x的最大值)。仔细一想这正是一个同构子问题!

    每一次都这样做,我们最多会扩大几次考虑范围呢?不难发现只要还有答案成立,这一次扩大之后的考虑范围至少是上一次的两倍,所以最多也就log级别。

    于是我们只需要维护区间内小于等于某个数字的和就可以了,开心上一发主席树板子。

     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 using namespace std;
    13 const int MAXN=100005;
    14 
    15 int N,M,AA[MAXN],rank[MAXN],tot;
    16 struct persistable_segment_tree{
    17     static const int maxn=1900005;
    18     static const int maxm=100005;
    19     int root[maxm],np,lc[maxn],rc[maxn],sum[maxn];
    20     persistable_segment_tree(){ np=0; }
    21     void pushup(int now){ sum[now]=sum[lc[now]]+sum[rc[now]]; }
    22     void build(int &now,int L,int R){
    23         now=++np,lc[now]=rc[now]=sum[now]=0;
    24         if(L==R) return;
    25         int m=L+R>>1;
    26         build(lc[now],L,m); build(rc[now],m+1,R);
    27     }
    28     int copynode(int now){
    29         np++,lc[np]=lc[now],rc[np]=rc[now],sum[np]=sum[now];
    30         return np;
    31     }
    32     void update(int &now,int L,int R,int pos,int v){
    33         now=copynode(now);
    34         if(L==R){ sum[now]+=v; return; }
    35         int m=L+R>>1;
    36         if(pos<=m) update(lc[now],L,m,pos,v);
    37         else update(rc[now],m+1,R,pos,v);
    38         pushup(now);
    39     }
    40     int query(int xx,int yy,int L,int R,int A,int B){
    41         if(A<=L&&R<=B) return sum[yy]-sum[xx];
    42         int m=L+R>>1;
    43         if(B<=m) return query(lc[xx],lc[yy],L,m,A,B);
    44         if(A>m) return query(rc[xx],rc[yy],m+1,R,A,B);
    45         return query(lc[xx],lc[yy],L,m,A,B)+query(rc[xx],rc[yy],m+1,R,A,B);
    46     }
    47 }st;
    48 
    49 void data_in()
    50 {
    51     scanf("%d",&N);
    52     for(int i=1;i<=N;i++) scanf("%d",&AA[i]);
    53     scanf("%d",&M);
    54 }
    55 void work()
    56 {
    57     memcpy(rank,AA,sizeof(AA));
    58     sort(rank+1,rank+N+1);
    59     tot=unique(rank+1,rank+N+1)-rank;
    60     st.build(st.root[0],1,tot-1);
    61     for(int i=1;i<=N;i++){
    62         st.root[i]=st.root[i-1];
    63         st.update(st.root[i],1,tot-1,lower_bound(rank+1,rank+tot,AA[i])-rank,AA[i]);
    64     }
    65     int l,r,pos,ans,tmp;
    66     for(int i=1;i<=M;i++){
    67         scanf("%d%d",&l,&r);
    68         pos=upper_bound(rank+1,rank+tot,1)-rank-1,ans=1;
    69         while(pos){
    70             tmp=st.query(st.root[l-1],st.root[r],1,tot-1,1,pos);
    71             if(tmp<ans) break;
    72             ans=tmp+1;
    73             if(pos==tot-1) break;
    74             pos=upper_bound(rank+1,rank+tot,ans)-rank-1;
    75         }
    76         printf("%d
    ",ans);
    77     }
    78 }
    79 int main()
    80 {
    81     data_in();
    82     work();
    83     return 0;
    84 }
  • 相关阅读:
    负数之美
    css重设
    编码问题
    wed的各种前端打印方法(3)CSS
    表单
    学习前端心得
    去除input,a,按键链接时出现的虚线方法
    加载事件js代码
    深入C#数据类型
    查找
  • 原文地址:https://www.cnblogs.com/KKKorange/p/8572176.html
Copyright © 2011-2022 走看看