zoukankan      html  css  js  c++  java
  • P1816 忠诚

    P1816 忠诚

    题目描述

    老管家是一个聪明能干的人。他为财主工作了整整10年,财主为了让自已账目更加清楚。要求管家每天记k次账,由于管家聪明能干,因而管家总是让财主十分满意。但是由于一些人的挑拨,财主还是对管家产生了怀疑。于是他决定用一种特别的方法来判断管家的忠诚,他把每次的账目按1,2,3…编号,然后不定时的问管家问题,问题是这样的:在a到b号账中最少的一笔是多少?为了让管家没时间作假他总是一次问多个问题。

    输入输出格式

    输入格式:

    输入中第一行有两个数m,n表示有m(m<=100000)笔账,n表示有n个问题,n<=100000。

    第二行为m个数,分别是账目的钱数

    后面n行分别是n个问题,每行有2个数字说明开始结束的账目编号。

    输出格式:

    输出文件中为每个问题的答案。具体查看样例。

    输入输出样例

    输入样例#1: 复制
    10 3
    1 2 3 4 5 6 7 8 9 10
    2 7
    3 9
    1 10
    输出样例#1: 复制
    2 3 1

    测试数据还有:

    100 100
    30634 1463 36025 59785 78967 ...

    80 93
    52 77
    79 93
    2 4
    1 73

    ...

    ...

    求区间最小值,线段树,树状数组都行。

    这里的树状数组记录的就是前面部分中最小的,或者说是前缀中最小的。

    洛谷题解:

    好吧,老是用线段树就没意思了。

    这道题又不需要对区间进行修改操作

    直接用树状数组就行了

    每个节点都是lowbit上来的点的最小值即可

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstdlib>
      4 #include<cstring>
      5 #include<cmath>
      6 #include<algorithm>
      7 #include <bits/stdc++.h>
      8 using namespace std;
      9 int a[1000001];    
     10 int tree[1000001];   
     11 int n,m;
     12 void printA(){
     13     cout<<"a数组:"<<endl;
     14     cout<<setw(10)<<" i:"<<" ";
     15     for(int i=1;i<=n;i++){
     16         cout<<i<<" ";
     17     } 
     18     cout<<endl;
     19     cout<<setw(10)<<" a[i]:"<<" ";
     20     for(int i=1;i<=n;i++){
     21         cout<<a[i]<<" ";
     22     } 
     23     cout<<endl;
     24 }
     25 void printTree(){
     26     cout<<"tree数组:"<<endl;
     27     cout<<setw(10)<<" i:"<<" ";
     28     for(int i=1;i<=n;i++){
     29         cout<<i<<" ";
     30     } 
     31     cout<<endl;
     32     cout<<setw(10)<<" tree[i]:"<<" ";
     33     for(int i=1;i<=n;i++){
     34         cout<<tree[i]<<" ";
     35     } 
     36     cout<<endl;
     37 }
     38 int lowbit(int x)
     39 {
     40     return x&(-x);
     41 }
     42 //update(i,a[i]);
     43 void update(int x,int v)
     44 {
     45     printTree();
     46     cout<<"x: "<<x<<"     v:"<<v<<endl;
     47     while(x<=n)
     48     {
     49         if(tree[x]>v)
     50           tree[x]=v;
     51          else
     52           return;     
     53         x+=lowbit(x);  
     54     }
     55 }
     56 int getmin(int x,int y)
     57 {
     58     int now=y;
     59     int maxl=2147483647;
     60     //如果区间尾大于区间头 
     61     while(now>=x)
     62     {
     63         //如果能跳到前一级区间,前一级区间没有越界 
     64         if(now-lowbit(now)>x)
     65         {
     66            maxl=min(maxl,tree[now]);
     67            now-=lowbit(now);
     68         }
     69         //如果不能跳,就往前遍历 
     70         else
     71         {
     72             maxl=min(maxl,a[now]);
     73             --now;
     74         }
     75     }
     76     return maxl;
     77 }
     78 
     79 int main()
     80 {
     81     freopen("in2.txt","r",stdin);
     82     memset(tree,127,sizeof(tree));
     83     cin>>n>>m;
     84     int x,y;
     85     //n++;
     86     cout<<endl<<"----------初始化树状数组----------"<<endl<<endl;
     87     for(int i=1;i<=n;++i)
     88     {
     89         cin>>a[i];
     90         update(i,a[i]);
     91     }
     92     printTree();
     93     printA(); 
     94     //tree数组记录的是区间的最小值 
     95     cout<<endl<<"----------求区间最小----------"<<endl<<endl; 
     96     for(;m>0;--m)
     97     {
     98         cin>>x>>y;
     99         cout<<getmin(x,y)<<' ';
    100     }
    101     return 0; 
    102 }

     运行过程:


    ----------初始化树状数组----------

    tree数组:
    i: 1 2 3 4 5 6 7 8 9 10
    tree[i]: 2139062143 2139062143 2139062143 2139062143 2139062143 2139062143 2139062143 2139062143 2139062143 2139062143
    x: 1 v:1
    tree数组:
    i: 1 2 3 4 5 6 7 8 9 10
    tree[i]: 1 1 2139062143 1 2139062143 2139062143 2139062143 1 2139062143 2139062143
    x: 2 v:2
    tree数组:
    i: 1 2 3 4 5 6 7 8 9 10
    tree[i]: 1 1 2139062143 1 2139062143 2139062143 2139062143 1 2139062143 2139062143
    x: 3 v:3
    tree数组:
    i: 1 2 3 4 5 6 7 8 9 10
    tree[i]: 1 1 3 1 2139062143 2139062143 2139062143 1 2139062143 2139062143
    x: 4 v:4
    tree数组:
    i: 1 2 3 4 5 6 7 8 9 10
    tree[i]: 1 1 3 1 2139062143 2139062143 2139062143 1 2139062143 2139062143
    x: 5 v:5
    tree数组:
    i: 1 2 3 4 5 6 7 8 9 10
    tree[i]: 1 1 3 1 5 5 2139062143 1 2139062143 2139062143
    x: 6 v:6
    tree数组:
    i: 1 2 3 4 5 6 7 8 9 10
    tree[i]: 1 1 3 1 5 5 2139062143 1 2139062143 2139062143
    x: 7 v:7
    tree数组:
    i: 1 2 3 4 5 6 7 8 9 10
    tree[i]: 1 1 3 1 5 5 7 1 2139062143 2139062143
    x: 8 v:8
    tree数组:
    i: 1 2 3 4 5 6 7 8 9 10
    tree[i]: 1 1 3 1 5 5 7 1 2139062143 2139062143
    x: 9 v:9
    tree数组:
    i: 1 2 3 4 5 6 7 8 9 10
    tree[i]: 1 1 3 1 5 5 7 1 9 9
    x: 10 v:10
    tree数组:
    i: 1 2 3 4 5 6 7 8 9 10
    tree[i]: 1 1 3 1 5 5 7 1 9 9
    a数组:
    i: 1 2 3 4 5 6 7 8 9 10
    a[i]: 1 2 3 4 5 6 7 8 9 10

    ----------求区间最小----------

    2 3 1

    这里的树状数组记录的就是前面部分中最小的,或者说是前缀中最小的。

    来一个不太一样的解法:离线+单调队列。

    先把所有询问读进来按右端点排序(这里我用了基数排序),然后按顺序将每个点插入队列。插入队列的时候如果队尾的元素的大于待插入的元素就弹出,这样就保证队列内的元素是递增的。

    对于每个询问,在这个询问的右端点被插入后,在队列中二分下标大于等于左端点的第一个数,由于队列是递增的,所以二分出来的数就是答案。

    这样做常数要比线段树小很多。

    #include<cstdio>
    #include<algorithm>
    #include<vector>
    using namespace std;
    struct data{int l,num;}; vector<data> G[100001];
    int a[100001],ans[100001],Q[100001],l=1,r=0;
    int main(){
        int n,m; scanf("%d%d",&n,&m);
        for(int i=1;i<=n;++i) scanf("%d",&a[i]);
        for(int i=1;i<=m;++i){
            int l,r; scanf("%d%d",&l,&r); G[r].push_back({l,i});
        }
        for(int i=1;i<=n;++i){
            for(;l<=r&&a[Q[r]]>=a[i];--r); Q[++r]=i;
            for(int j=0;j<G[i].size();++j) ans[G[i][j].num]=a[*lower_bound(Q+l,Q+r+1,G[i][j].l)];
        }
        for(int i=1;i<=m;++i) printf("%d ",ans[i]); return 0;
    }
  • 相关阅读:
    [学习笔记]基于值域预处理的快速 GCD
    [学习笔记]整除偏序与zeta变换、Möbius变换、lcm卷积、gcd卷积
    [学习笔记]MinMax容斥
    [学习笔记]Pollard Rho算法
    [学习笔记]Miller Rabin测试
    [学习笔记]万能欧几里得
    用C#写程序安装包 Joe
    linux 命令
    几个有用的php字符串过滤,转换函数
    linux挂载 Windows分区
  • 原文地址:https://www.cnblogs.com/Renyi-Fan/p/7743270.html
Copyright © 2011-2022 走看看