• Queue


    题目描述

    一个简单的数列问题:

    给定一个长度为n的数列,求这样的三个元素 ai,aj,ak 的个数,满足 ai< aj >ak,且 i<j<k。

    输入输出格式

    输入格式:

     

    第1行是一个整数n(1<= n <= 50000)。

    接下来n行,每行一个元素ai(0< = ai <= 32767)。

     

    输出格式:

     

    一个数,满足 ai< aj >ak (i < j < k) 的个数。

    输入输出样例

    输入样例

    5
    1
    2
    3
    4
    1

    输出样例

    6

    这道题我是这么想的,就是枚举 j, 然后分别找出符合条件的 ai 和 ak,

    比如一个数列:2,4,6,1,7,8,2,5,3,9,当 aj 枚举到 aj = 7 的时候,查找[1, j],发现比 aj 小的数有4个,在查找 [j, n],发现比 aj 小的数有3个,那么此时j = 5 时,满足题意的数的个数就是4 * 3=12个,ans += 12。

    那这道题就是一道动态区间查询数值大小的题了,最简单的想法就是对于每一次查找,分别遍历 [1, j] 和 [j, n],然而时间复杂度是 O(n * n),只能得部分分。

    于是我又看了一眼数据范围,发现 0< = ai <= 32767,于是我马上想到了用线段树,且线段树的范围是值域([0, 32767]),而不是总共的个数500000。这样查询一个 aj,就能用(Ologn)的复杂度知道比aj小的数有多少个了,为此我就用了两个线段树,一个负责处理[1, j] 的数中比 aj小的数,另一个处理[j, n]。

    遍历 j 的时候,前一个线段树每一次添加 aj,后一个线段树删除a[j - 1],(所以后面的线段树要先将所有元素添加进去)然后分别查询[1, 32767]中符合题意的个数。

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<cstring>
     4 #include<cmath>
     5 #include<algorithm>
     6 using namespace std;
     7 const int maxn = 5e4 + 5;
     8 typedef long long ll;
     9 ll ans = 0;
    10 int n, a[maxn];
    11 struct Tree            //打包,方便 
    12 {
    13     int l[4 * maxn], r[4 * maxn], num[4 * maxn];
    14     void init()
    15     {
    16         for(int i = 0; i < 4 * maxn; ++i)
    17             l[i] = r[i] = num[i] = 0;
    18     }
    19     /*一定要有这个建树函数,要不然查询时可能会访问到没有声明的结点 ,
    20     结果就PE了。刚开始我没加,d了一个晚上都没d出来……*/ 
    21     void build(int L, int R, int now)        
    22     {
    23         l[now] = L; r[now] = R;
    24         if(L == R) return;
    25         int mid = (L + R) >> 1;
    26         build(L, mid, now << 1);
    27         build(mid + 1, R, now << 1 | 1);
    28     }
    29     void update(int L, int R, int idx, int d, int now)
    30     {
    31         l[now] = L; r[now] = R;
    32         if(l[now] == r[now])
    33         {
    34             num[now] += d; 
    35             return;
    36         }
    37         int mid = (l[now] + r[now]) >> 1;
    38         if(idx <= mid) update(L, mid, idx, d, now << 1);
    39         else update(mid + 1, R, idx, d, now << 1 | 1);
    40         num[now] = num[now << 1] + num[now << 1 | 1];
    41     }
    42     int query(int L, int R, int now)
    43     {
    44         if(L == l[now] && R == r[now]) return num[now];
    45         int mid = (l[now] + r[now]) >> 1;
    46         if(R <= mid) return query(L, R, now << 1);
    47         else if(L > mid) return query(L, R, now << 1 | 1);
    48         else return query(L, mid, now << 1) + query(mid + 1, R, now << 1 | 1);
    49     }
    50 }treeHead, treeTail;
    51 int main()
    52 {
    53     treeHead.init(); treeTail.init();
    54     scanf("%d", &n);
    55     treeHead.build(1, maxn, 1); treeTail.build(1, maxn, 1);
    56     for(int i = 1; i <= n; ++i) {scanf("%d", &a[i]); a[i] += 2; treeTail.update(1, maxn, a[i], 1, 1);}
    57     //a[i] += 2 是为了防止a[i] = 0 的情况,因为查询区间是[1, maxn] 
    58     treeHead.update(1, maxn, a[1], 1, 1);
    59     for(int i = 2; i < n; ++i)
    60     {
    61         treeHead.update(1, maxn, a[i], 1, 1); treeTail.update(1, maxn, a[i - 1], -1, 1);
    62         ll temp = (ll)treeHead.query(1, a[i] - 1, 1) * treeTail.query(1, a[i] - 1, 1);
    63         ans += temp; 
    64     }
    65     printf("%lld
    ", ans);
    66     return 0;
    67 }
  • 相关阅读:
    paddlepaddle训练网络的基本流程二(进阶Paddle-detection框架)
    paddlepaddle训练网络的基本流程一(入门示例)
    redis常用操作命令
    mysql基础命令
    使用Gunicorn和nginx进行Flask服务部署
    如何测试(八)抖音 如何测试?
    全(十九)Jmeter 请求 之 遇到 cookie、token 处理方式(使用 正则表达式提取器 获取 然后在引用)
    全(十八)Jmeter 请求元件 之 JSON PATH 提取 响应结果
    全(十七)Jmeter 请求元件 之 正则表达式提取器 提取 响应结果、foreach循环控制器
    全(十六)Jmeter 请求 之 正则表达式
  • 原文地址:https://www.cnblogs.com/mrclr/p/8502590.html
Copyright © 2020-2023  润新知