2016 Multi-University Training Contest 5 1012 World is Exploding 树状数组+离线化

1012 World is Exploding

题意:选四个数,满足a<b and A[a]<A[b]   c<d and A[c]>A[d] 问有几个这样的集合

思路:

树状数组+离线化

先处理出每个数左边比它小 大,右边比它大 小的数目,用cnt[][i]表示。最后统计一下减去重复的就可以

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <sstream>
  5 #include <string>
  6 #include <algorithm>
  7 #include <list>
  8 #include <map>
  9 #include <vector>
 10 #include <queue>
 11 #include <stack>
 12 #include <cmath>
 13 #include <cstdlib>
 14 using namespace std;
 15 typedef long long ll;
 16 ll cnt[4][50005];
 17 ll cnt1[50005],cnt2[50005];
 18 ll a[50005];
 19
 20 struct Node{
 21     ll num,id;
 22 }sub_a[50005];
 23
 24
 25 ll maxn = 0;
 26 ll n;
 27 ll tree[100005];
 28 bool cmp(Node a, Node b) { //按照数字排序
 29     return a.num < b.num;
 30 }
 31 void discrete() { //离散化
 32     sort(sub_a+1, sub_a+1+n, cmp);
 33     a[sub_a[1].id] = 1;
 34     maxn = 1;
 35     for(ll i = 2; i <= n; i++) {
 36         if(sub_a[i].num != sub_a[i-1].num)
 37             a[sub_a[i].id] = i;
 38         else
 39             a[sub_a[i].id] = a[sub_a[i-1].id];
 40         maxn = max(maxn,a[sub_a[i].id]);
 41     }
 42 }
 43 void add(ll k){
 44     while(k <= n){
 45         tree[k] ++;
 46         k += k & (- k);
 47     }
 48 }
 49 ll read(ll k){
 50     ll ans = 0;
 51     while(k){
 52         ans += tree[k];
 53         k -= k &(-k);
 54     }
 55     return ans;
 56 }
 57
 58 int main(){
 59     while(scanf("%I64d",&n) != EOF)
 60     {
 61         memset(cnt1,0,sizeof(cnt1));
 62         memset(cnt2,0,sizeof(cnt2));
 63         for(ll i = 1; i <= n; i ++){
 64             scanf("%I64d",&sub_a[i].num);
 65             sub_a[i].id = i;
 66         }
 67         discrete();
 68         memset(tree,0,sizeof(tree));
 69         //在它右侧比它小的
 70         for(ll i = n; i >= 1; i--){
 71
 72             add(a[i]);
 73            cnt[0][i] = read(a[i] - 1);
 74         }
 75         //在它左侧比它小的
 76          memset(tree,0,sizeof(tree));
 77         for(ll i = 1; i <= n; i ++){
 78             add(a[i]);
 79             cnt[1][i] = read(a[i] - 1);
 80             a[i] = maxn + 1 - a[i];
 81         }
 82          //在它右侧比它大的
 83           memset(tree,0,sizeof(tree));
 84         for(ll i = n; i >= 1; i --){
 85
 86             add(a[i]);
 87            cnt[2][i] = read(a[i] - 1);
 88         }
 89         //在它左侧比它大的
 90          memset(tree,0,sizeof(tree));
 91         for(ll i = 1; i <= n; i ++){
 92             add(a[i]);
 93             cnt[3][i] = read(a[i] - 1);
 94             a[i] = maxn + 1 - a[i];
 95         }
 96         ll cnta = 0,cntb = 0;
 97         for(ll i = 1; i <= n; i ++){
 98             cnt1[i] = cnt[0][i] + cnt[3][i];
 99             cnta += cnt1[i];
100             cnt2[i] = cnt[1][i] + cnt[2][i];
101              cntb += cnt2[i];
102         }
103         cnta = cnta / 2;
104         cntb = cntb / 2;
105         long long  ans = cnta * cntb;
106         for(ll i = 1; i <= n; i ++){
107             ans -= cnt1[i] * cnt2[i];
108         }
109         printf("%I64d\n",ans);
110     }
111     return 0;
112 }
时间: 2024-07-31 14:31:39

2016 Multi-University Training Contest 5 1012 World is Exploding 树状数组+离线化的相关文章

AtCoder Regular Contest 088 E - Papple Sort(树状数组+结论)

结论:每次把字符丢到最外面最优,用树状数组统计答案,把字符放到最外边后可以当成消失了,直接在树状数组上删掉就好. 感性理解是把字符丢到中间会增加其他字符的移动次数,但是丢到外面不会,所以是正确的. #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #define ll long long using namespace std; const int maxn=500

hdu 5775 Bubble Sort(2016 Multi-University Training Contest 4——树状数组)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5775 Bubble Sort Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 636    Accepted Submission(s): 378 Problem Description P is a permutation of the

AtCoder Regular Contest 075 E - Meaningful Mean 树状数组求顺序对, 前缀和

题目链接: http://arc075.contest.atcoder.jp/tasks/arc075_c 题意: 给你一个序列和一个数k,求有多少对l,r,使得a[l]+a[l+1]+...+a[r]的算术平均数大于等于k 1≤N≤2×10^5 1≤K≤10^9 1≤ai≤10^9 思路: 首先对于所有数减去k,这样就不用除(r-l+1), 然后我们发现所求的就是有多少对l,r,使得sum[r]-sum[l-1] >= 0, sum是减去k之后的序列的前缀和 用树状数组对sum求有多少个顺序对

【BZOJ】1012: [JSOI2008]最大数maxnumber(树状数组+区间最值)

http://www.lydsy.com/JudgeOnline/problem.php?id=1012 树状数组原来我只懂得sum和add的操作,今天才知道可以有求区间最值的操作,我学习了一下写了个,1a了. 区间最值其实和区间求和差不多,就是将sum数组的含义转移到max,然后通过特定的区间更新max. 在区间求和中,当我们维护max[i]的时候,要找到它前面所有的max[j]来更新,在这里因为是树状数组,所以可以降成一个log级,画图可知,max[i]需要的max只有max[i-2^0],

hdu 5792 World is Exploding(2016 Multi-University Training Contest 5——树状数组)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5792 World is Exploding Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 643    Accepted Submission(s): 306 Problem Description Given a sequence A

2019 Multi-University Training Contest 3 Find the answer (离散化+二分+树状数组)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6609 题目大意:给定一个含有n个数的序列,还有一个m,对于每个i(1<=i<=n)求出最少需要将前i-1个数中的多少个数改成0,才能使得前i个数的和小于m 解题思路:很容易想到,我们应该将比较大的数变为0,答案才是最优的.所以我们直接给他们排个序离散化一下,对应它们在树上的编号,树上节点存两个东西,一个是节点的权值之和,还有一个就是包含数的个数,每次查询时,先将前i-1个数更新到树上,可以保证后面

BZOJ 1012: [JSOI2008]最大数maxnumber 单调队列/线段树/树状数组/乱搞

1012: [JSOI2008]最大数maxnumber Time Limit: 3 Sec  Memory Limit: 162 MBSubmit: 4750  Solved: 2145[Submit][Status][Discuss] Description 现 在请求你维护一个数列,要求提供以下两种操作: 1. 查询操作.语法:Q L 功能:查询当前数列中末尾L个数中的最大的数,并输出这个数的值.限制:L不超过当前数列的长度. 2. 插入操作.语法:A n 功能:将n加上t,其中t是最近一

AtCoder Regular Contest 075 E - Meaningful Mean(树状数组)

题目大意:求一个数组中,平均值不小于k的连续子序列个数 所有数减去k,算个前缀和出来,就变成二维数点问题了. 没有修改,离线的话就是CZL所说的"NOIP最喜欢的套路"了:倒着加进BIT,以权值为数组下标(权值BIT?233),询问比ai大的个数. PS:数组要从0开始算,不然会少算长度为1的连续子序列. #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio

2016 大连网赛---Weak Pair(dfs+树状数组)

题目链接 http://acm.split.hdu.edu.cn/showproblem.php?pid=5877 Problem Description You are given a rooted tree of N nodes, labeled from 1 to N. To the ith node a non-negative value ai is assigned.An ordered pair of nodes (u,v) is said to be weak if  (1) u