zoukankan      html  css  js  c++  java
  • 大视野 1012: [JSOI2008]最大数maxnumber(线段树/ 树状数组/ 单调队列/ 单调栈/ rmq)

    1012: [JSOI2008]最大数maxnumber

    Time Limit: 3 Sec  Memory Limit: 162 MB
    Submit: 9851  Solved: 4318
    [Submit][Status][Discuss]

    Description

      现在请求你维护一个数列,要求提供以下两种操作:1、 查询操作。语法:Q L 功能:查询当前数列中末尾L
    个数中的最大的数,并输出这个数的值。限制:L不超过当前数列的长度。2、 插入操作。语法:A n 功能:将n加
    上t,其中t是最近一次查询操作的答案(如果还未执行过查询操作,则t=0),并将所得结果对一个固定的常数D取
    模,将所得答案插入到数列的末尾。限制:n是非负整数并且在长整范围内。注意:初始时数列是空的,没有一个
    数。

    Input

      第一行两个整数,M和D,其中M表示操作的个数(M <= 200,000),D如上文中所述,满足D在longint内。接下来
    M行,查询操作或者插入操作。

    Output

      对于每一个询问操作,输出一行。该行只有一个数,即序列中最后L个数的最大数。

    Sample Input

    5 100
    A 96
    Q 1
    A 97
    Q 1
    Q 2

    Sample Output

    96
    93
    96

    HINT

      数据如下http://pan.baidu.com/s/1i4JxCH3

    Source

    线段树

      1 #include <bits/stdc++.h>
      2 using namespace std;
      3 
      4 #define L(root) ((root) << 1)
      5 #define R(root) (((root) << 1) | 1)
      6 
      7 const int MAXN = 200000 + 5;
      8 int numbers[MAXN];
      9 
     10 struct Node {
     11     int left, right;
     12     //int sum;//
     13     int mx;//最大值
     14     int mid()
     15     {
     16         return left + ((right - left) >> 1);
     17     }
     18 } tree[MAXN * 4];
     19 
     20 void pushUp(int root)
     21 {
     22 //    tree[root].sum = tree[L(root)].sum + tree[R(root)].sum;
     23     tree[root].mx = max(tree[L(root)].mx, tree[R(root)].mx);
     24 }
     25 
     26 void build(int root, int left, int right)
     27 {
     28     tree[root].left = left;
     29     tree[root].right = right;
     30     if (left == right) {
     31 //        tree[root].sum = numbers[left];
     32         tree[root].mx = 0;
     33         return;
     34     }
     35     int mid = tree[root].mid();
     36     build(L(root), left, mid);
     37     build(R(root), mid + 1, right);
     38     pushUp(root);
     39 }
     40 
     41 int query(int root, int left, int right)
     42 {
     43     if (tree[root].left == left && tree[root].right == right) {
     44 //        return tree[root].sum;
     45         return tree[root].mx;
     46     }
     47     int mid = tree[root].mid();
     48     if (right <= mid) {
     49         return query(L(root), left, right);
     50     } else if (left > mid) {
     51         return query(R(root), left, right);
     52     } else {
     53         //return query(L(root), left, mid) + query(R(root), mid + 1, right);
     54         //注意返回最大值...
     55         int lv = query(L(root), left, mid);
     56         int rv = query(R(root), mid + 1, right);
     57         return lv > rv ? lv : rv;
     58     }
     59 }
     60 
     61 void update(int root, int pos, int add)
     62 {
     63     if (tree[root].left == tree[root].right) {
     64         //tree[root].sum = tree[root].sum + add;
     65         tree[root].mx = add;
     66         return;
     67     }
     68     int mid = tree[root].mid();
     69     if (pos <= mid) {
     70         update(L(root), pos, add);
     71     } else {
     72         update(R(root), pos, add);
     73     }
     74     pushUp(root);
     75 }
     76 
     77 void test01()
     78 {
     79     memset(numbers, 0, sizeof(numbers));
     80     int i;
     81     for (i = 1; i < MAXN; ++i) {
     82         numbers[i] = i;
     83     }
     84     build(1, 1, 10);
     85     printf("%d
    ", query(1, 2, 3));
     86     update(1, 2, 100);
     87     printf("%d
    ", query(1, 2, 3));
     88 }
     89 
     90 int main()
     91 {
     92     //test01();
     93 
     94     int M, D;
     95     char str[2];
     96     int x;
     97     int i;
     98     int t;
     99     int len;//当前长度
    100 
    101     while (~scanf("%d%d", &M, &D)) {
    102         build(1, 1, M);
    103 
    104         t = 0;
    105         len = 0;
    106         for (i = 0; i < M; ++i) {
    107             scanf("%1s%d", str, &x);
    108             if (str[0] == 'Q') {
    109                 t = query(1, len - x + 1, len);
    110                 printf("%d
    ", t);
    111             } else {
    112                 update(1, ++len, (x + t) % D);
    113             }
    114         }
    115     }
    116 
    117     return 0;
    118 }
    View Code

    树状数组(代码好难理解,日后再看)

    区间最值其实和区间求和差不多,就是将sum数组的含义转移到max,然后通过特定的区间更新max。
    
    在区间求和中,当我们维护max[i]的时候,要找到它前面所有的max[j]来更新,在这里因为是树状数组,所以可以降成一个log级,画图可知,max[i]需要的max只有max[i-2^0],max[i-2^1],max[i-2^2]..max[i-lowbit(i)+1]
    
    更新操作简单,即
    
    void change(int r) {
        c[r]=num[r];
        for(int i=1; i<lowbit(r); i<<=1)
            c[r]=max(c[r], c[r-i]);
    }
    接下来是求区间最值,很容易看出,我们找[l,r]的最值就是找在次区间的max,即递减r,在这里可以有个优化,即当找到一个max[i],有i-lowbit(i)>=l时,更新后,i直接-=lowbit(i),然后继续递减。当l>=r就跳出循环
    
    int getk(int l, int r) {
        int ret=num[r];
        while(l<=r) {
            ret=max(ret, num[r]);
            for(--r; r-l>=lowbit(r); r-=lowbit(r))
                ret=max(ret, c[r]);
        }
        return ret;
    }
    其实在这里更新操作可以和区间最值放在一起,(现在用c代表max)即c[i]=max(getk(i-lowbit(i)+1, i), num[i]);
    View Code
     1 #include <cstdio>
     2 using namespace std;
     3 #define lowbit(x) (x&-x)
     4 #define max(a,b) ((a)>(b)?(a):(b))
     5 const int N=200005;
     6 int num[N], c[N], cnt;
     7 int getk(int l, int r) {
     8     int ret=num[r];
     9     while(l<=r) {
    10         ret=max(ret, num[r]);
    11         for(--r; r-l>=lowbit(r); r-=lowbit(r))
    12             ret=max(ret, c[r]);
    13     }
    14     return ret;
    15 }
    16 
    17 int main() {
    18     int n, d, t=0, a;
    19     char ch[3];
    20     scanf("%d%d", &n, &d);
    21     while(n--) {
    22         scanf("%s%d", ch, &a);
    23         if(ch[0]=='A') {
    24             num[++cnt]=(t+a)%d;
    25             c[cnt]=max(getk(cnt-lowbit(cnt)+1, cnt-1), num[cnt]);
    26         }
    27         else {
    28             printf("%d
    ", t=getk(cnt-a+1, cnt));
    29         }
    30     }
    31     return 0;
    32 }
    View Code

    单调递减队列/ 单调递增栈

     1 #include <iostream>
     2 #include <cstdlib>
     3 #include <cstdio>
     4 #include <cstring>
     5 #include <algorithm>
     6 #include <climits>
     7 #define N 1000000
     8 #define INF INT_MAX
     9 
    10 using namespace std;
    11 
    12 //单调递减队列, [队首, 队尾], [3, 2, 1], 队列中存下标
    13 //单调递增栈, [栈底, 栈顶], [3, 2, 1]
    14 int q[N],m,d,h=1,t=1,num;
    15 int val[N],ans;
    16 
    17 //二分找到x后面第一个数
    18 inline int getans(int x)
    19 {
    20     int l=h,r=t-1,mid,res;
    21     while(l<=r)
    22     {
    23         mid=(l+r)>>1;
    24         if(x<=q[mid]) res=mid,r=mid-1;
    25         else l=mid+1;
    26     }
    27     return q[res];
    28 }
    29 
    30 inline void go()
    31 {
    32     scanf("%d%d",&m,&d);
    33     int a;
    34     char str[10];
    35     while(m--)
    36     {
    37         scanf("%s%d",str,&a);
    38         if(str[0]=='A')
    39         {
    40             val[++num]=(a+ans)%d;
    41             while(h<t&&val[q[t-1]]<=val[num]) t--;
    42             q[t++]=num;
    43         }
    44         else
    45         {
    46             //二分
    47             ans=val[getans(num-a+1)];
    48             printf("%d
    ",ans);
    49         }
    50     }
    51 }
    52 
    53 int main()
    54 {
    55     go();
    56     return 0;
    57 }
    View Code

    下面的代码比较挫了,如果输入序列递增,估计要超时。辅助理解单调队列思想。

     1 //qscqesze
     2 #include <cstdio>
     3 #include <cmath>
     4 #include <cstring>
     5 #include <ctime>
     6 #include <iostream>
     7 #include <algorithm>
     8 #include <set>
     9 #include <vector>
    10 #include <sstream>
    11 #include <queue>
    12 #include <typeinfo>
    13 #include <fstream>
    14 #include <map>
    15 typedef long long ll;
    16 using namespace std;
    17 //freopen("D.in","r",stdin);
    18 //freopen("D.out","w",stdout);
    19 #define sspeed ios_base::sync_with_stdio(0);cin.tie(0)
    20 #define maxn 250001
    21 #define eps 1e-9
    22 const int inf=0x7fffffff;   //无限大 
    23 //**************************************************************************************
    24 int a[maxn],max_num[maxn],t=0,ans=0;
    25 int main()
    26 {
    27     int n,d;
    28     scanf("%d%d",&n,&d);
    29     char ch[3];
    30     int g;
    31     while(n--)
    32     {
    33         scanf("%s%d",ch,&g);
    34         if(ch[0]=='A')
    35         {
    36             a[++t]=(ans+g)%d;
    37             for(int i=t;i;i--)
    38             {
    39                 if(max_num[i]<a[t])
    40                     max_num[i]=a[t];
    41                 else
    42                     break;
    43             }
    44         }
    45         else
    46         {
    47             ans=max_num[t-g+1];
    48             printf("%d
    ",ans);
    49         }
    50     }
    51     return 0;
    52 }
    View Code

    rmq(我写的这个速度有点捉急...)

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 const int MAXN = 200000 + 5;
     5 int mx[MAXN][20];
     6 int num[MAXN];
     7 int tot;
     8 
     9 void update()
    10 {
    11     mx[tot][0] = num[tot];
    12     int k1 = log2(tot);
    13     int k2;
    14     int i, j;
    15     for (j = 1; j <= k1; ++j) {
    16         k2 = tot - pow(2, j) + 1;
    17         for (i = k2; i <= k2; ++i) {
    18             mx[i][j] = max(mx[i][j - 1], mx[i + (int)pow(2, j - 1)][j - 1]);
    19         }
    20     }
    21 }
    22 
    23 int rmq(int i, int j)
    24 {
    25     int k = log2(j - i + 1);
    26     return max(mx[i][k], mx[j - (int)pow(2, k) + 1][k]);
    27 }
    28 
    29 int main()
    30 {
    31     int M, D;
    32     char str[2];
    33     int x;
    34     int i;
    35     int t;
    36 
    37     while (~scanf("%d%d", &M, &D)) {
    38         tot = 0;
    39         t = 0;
    40         for (i = 0; i < M; ++i) {
    41             scanf("%1s%d", str, &x);
    42             if (str[0] == 'Q') {
    43                 t = rmq(tot - x + 1, tot);
    44                 printf("%d
    ", t);
    45             } else {
    46                 num[++tot] = (x + t) % D;
    47                 update();
    48             }
    49         }
    50     }
    51 
    52     return 0;
    53 }
    View Code
  • 相关阅读:
    iOS屏幕旋转
    iOS使用NSURLSession发送POST请求,后台无法接受到请求过来的参数
    iOS NET Error Code
    Android App在Google App Store中搜不到
    postman中 form-data、x-www-form-urlencoded、raw、binary的区别
    Android的缓存图片不在系统图库中显示的解决办法
    Android的Notification相关设置
    iOS+PHP图片上传
    解决ndk编译lua时遇到 undefined reference to '__srget'的问题
    避免修改Android.mk添加cpp文件路径
  • 原文地址:https://www.cnblogs.com/gongpixin/p/6757473.html
Copyright © 2011-2022 走看看