AcWing:241. 楼兰图腾(树状数组逆序对)

在完成了分配任务之后,西部314来到了楼兰古城的西部。

相传很久以前这片土地上(比楼兰古城还早)生活着两个部落,一个部落崇拜尖刀(‘V’),一个部落崇拜铁锹(‘∧’),他们分别用V和∧的形状来代表各自部落的图腾。

西部314在楼兰古城的下面发现了一幅巨大的壁画,壁画上被标记出了N个点,经测量发现这N个点的水平位置和竖直位置是两两不同的。

西部314认为这幅壁画所包含的信息与这N个点的相对位置有关,因此不妨设坐标分别为(1,y1),(2,y2),…,(n,yn)(1,y1),(2,y2),…,(n,yn),其中y1y1~ynyn是1到n的一个排列。

西部314打算研究这幅壁画中包含着多少个图腾。

如果三个点(i,yi),(j,yj),(k,yk)(i,yi),(j,yj),(k,yk)满足1≤i<j<k≤n且yi>yj,yj<yk1≤i<j<k≤n且yi>yj,yj<yk,则称这三个点构成V图腾;

如果三个点(i,yi),(j,yj),(k,yk)(i,yi),(j,yj),(k,yk)满足1≤i<j<k≤n且yi<yj,yj>yk1≤i<j<k≤n且yi<yj,yj>yk,则称这三个点构成∧图腾;

西部314想知道,这n个点中两个部落图腾的数目。

因此,你需要编写一个程序来求出V的个数和∧的个数。

输入格式

第一行一个数n。

第二行是n个数,分别代表y1,y2,…,yny1,y2,…,yn。

输出格式

两个数,中间用空格隔开,依次为V的个数和∧的个数。

数据范围

对于所有数据,n≤200000n≤200000,且输出答案不会超过int64。

输入样例:

5
1 5 3 2 4

输出样例:

3 4

题解:从1 ~ n顺着求一遍逆序对,大于当前值的个数记录到数组leftup,小于当前值的个数记录到数组leftdown。同理,从n ~ 1逆着求一遍逆序对,大于当前值的个数记录到数组rightup,小于当前值的个数记录到数组rightdown。然后就只需要再次遍历一遍数组,以当前值为中心点,求"v"的数量,就是(前面大于当前值的个数leftup[i] * 后面大于当前值的个数rightup[i])。求"^"的数量同理。

#include <iostream>
#include <cstdio>

using namespace std;

typedef long long ll;

const int maxn = 2e5+7;

int n;
int arr[maxn], tree[maxn];
ll leftup[maxn], rightup[maxn], leftdown[maxn], rightdown[maxn];

int lowbit(int x) {
    return x & (-x);
}

ll ask(int x) {
    ll res = 0;
    while(x >= 1) {
        res += tree[x];
        x -= lowbit(x);
    }
    return res;
}

void add(int x) {
    while(x <= n) {
        tree[x]++;
        x += lowbit(x);
    }
}

int main() {
    scanf("%d", &n);
    for(int i = 1; i <= n; i++) {
        scanf("%d", &arr[i]);
    }
    for(int i = 1; i <= n; i++) {
        leftdown[i] = ask(arr[i] - 1);
        leftup[i] = ask(n) - ask(arr[i]);
        add(arr[i]);
    }
    for(int i = 1; i <= n; i++) {
        tree[i] = 0;
    }
    for(int i = n; i >= 1; i--) {
        rightdown[i] = ask(arr[i] - 1);
        rightup[i] = ask(n) - ask(arr[i]);
        add(arr[i]);
    }
    ll ans1 = 0, ans2 = 0;
    for(int i = 1; i <= n; i++) {
        ans1 += leftup[i] * rightup[i];
        ans2 += leftdown[i] * rightdown[i];
    }
    cout << ans1 << " " << ans2 << endl;
    return 0;
}

原文地址:https://www.cnblogs.com/buhuiflydepig/p/11404025.html

时间: 2024-11-13 07:57:04

AcWing:241. 楼兰图腾(树状数组逆序对)的相关文章

hdu 5193 分块 树状数组 逆序对

题意: 给出n个数,a1,a2,a3,...,an,给出m个修改,每个修改往数组的某个位置后面插入一个数,或者把某个位置上的数移除.求每次修改后逆序对的个数. 限制: 1 <= n,m <= 20000; 1 <= ai <= n 思路: 插入和删除用分块来处理,块与块之间用双向链表来维护,每一块用树状数组来求小于某个数的数有多少个. 外层可以使用分块维护下标,这样添加和删除元素的时候,也很方便,直接暴力.查找权值个数时,使用树状数组比较方便.内层通过树状数组维护权值. 每次更新即

Bzoj 2789: [Poi2012]Letters 树状数组,逆序对

2789: [Poi2012]Letters Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 278  Solved: 185[Submit][Status][Discuss] Description 给出两个长度相同且由大写英文字母组成的字符串A.B,保证A和B中每种字母出现的次数相同. 现在每次可以交换A中相邻两个字符,求最少需要交换多少次可以使得A变成B. Input 第一行一个正整数n (2<=n<=1,000,000),表示字符串的长度

【树状数组逆序对】USACO.2011JAN-Above the median

[题意] 给出一串数字,问中位数大于等于X的连续子串有几个.(这里如果有偶数个数,定义为偏大的那一个而非中间取平均) [思路] 下面的数据规模也小于原题,所以要改成__int64才行.没找到测试数据,自己编的几组.简单来说读入每个数,大于等于中位数设为1,小于设为-1,前i个数的和建立一个树状数组,求逆序对. 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorit

Poj 2299 - Ultra-QuickSort 离散化,树状数组,逆序对

Ultra-QuickSort Time Limit: 7000MS   Memory Limit: 65536K Total Submissions: 52306   Accepted: 19194 Description In this problem, you have to analyze a particular sorting algorithm. The algorithm processes a sequence of n distinct integers by swappin

Codevs 3286 火柴排队 2013年NOIP全国联赛提高组 树状数组,逆序对

题目:http://codevs.cn/problem/3286/ 3286 火柴排队  2013年NOIP全国联赛提高组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题解 题目描述 Description 涵涵有两盒火柴,每盒装有 n 根火柴,每根火柴都有一个高度.现在将每盒中的火柴各自排成一列,同一列火柴的高度互不相同,两列火柴之间的距离定义为:,其中 ai表示第一列火柴中第 i 个火柴的高度,bi表示第二列火柴中第 i 个火柴的高度.每列火柴中相

总结之---树状数组+逆序对问题。

咳咳,这个图必须要的.... 首先,当有一个数组a数量非常大的时候,我们可能改变某个a[i]的值,要求a[n]的和,全部加起来,无疑是要O(n)的时间复杂度. 但是如果n非常大时,O(n)时间复杂度肯定要跪,所以,怎么办的,用神奇的树状数组. 树状数组代码简单,但是非常强大!更令人兴奋的是,它的时间复杂度值需要O(logn)!!! 好了,首先要的东西是把上图的c[n]表示出来,该怎么弄呢,代码如下: int lowbit(int t) { return t&(-t); } 这个代码,简单到爆,但

题解 SP4226 【MSE06H - Japan】(树状数组+逆序对)

原OJ提交点这里 这道题一开始让我很雾...... 不过 思路其实非常清晰:如果i<j a[i].x<a[j].x a[i].y>a[j].y 那么就会产生一个交点 大家画个图就出来了 具体操作也很好实现: 定义一个结构体 x升序排列 当x相同就y升序排列 按照我们的排序方式 把a[i].y踢出来跑树状数组求逆序对就可以了 附上AC代码 #include<cstdio> #include<iostream> #include<cmath> #inclu

Codeforces Round #609 (Div. 2)E--K Integers(贪心+二分+树状数组+逆序对)

K Integers 参考博客:https://blog.csdn.net/Q755100802/article/details/103664555 [题意] 给定一个1到n的排列,可以交换相邻的两个元素. 现在定义一个函数f(x),表示在原排列中,通过交换操作,形成一个1,2,3....x的排列的子串,需要的最小操作步骤. 子串意味着这个排列必须是相邻的.现在你需要求出f(1),f(2),f(3)......f(n). [分析] 在1~x这几个元素相邻的情况下,因为最后排列不存在逆序对,根据贪

HDU 2689Sort it 树状数组 逆序对

Sort it Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 4110    Accepted Submission(s): 2920 Problem Description You want to processe a sequence of n distinct integers by swapping two adjacent s

HDU - 2838 Cow Sorting (树状数组 + 逆序对)

HDU - 2838 Cow Sorting Time Limit: 1000MS   Memory Limit: 32768KB   64bit IO Format: %I64d & %I64u Submit Status Description Sherlock's N (1 ≤ N ≤ 100,000) cows are lined up to be milked in the evening. Each cow has a unique "grumpiness" lev