树状数组+逆序数与顺序数——HDU 2492

对应HDU题目:点击打开链接

Ping pong

Time Limit:3000MS     Memory Limit:0KB     64bit IO Format:%lld
& %llu

Submit Status

Description

N(3N20000) ping
pong players live along a west-east street(consider the street as a line segment). Each player has a unique skill rank. To improve their skill rank, they often compete with each other. If two players want to compete, they must choose a referee among other
ping pong players and hold the game in the referee‘s house. For some reason, the contestants can‘t choose a referee whose skill rank is higher or lower than both of theirs. The contestants have to walk to the referee‘s house, and because they are lazy, they
want to make their total walking distance no more than the distance between their houses. Of course all players live in different houses and the position of their houses are all different. If the referee or any of the two contestants is different, we call
two games different. Now is the problem: how many different games can be held in this ping pong street?

Input

The first line of the input contains an integer T(1T20) ,
indicating the number of test cases, followed by T lines each of which describes a test case.

Every test case consists of N + 1 integers. The first integer is N , the number of players. Then N distinct
integers a1a2...aN follow, indicating the skill rank of each player, in the order of west to east ( 1ai100000 , i =
1...N ).

Output

For each test case, output a single line contains an integer, the total number of different games.

Sample Input

1
3 1 2 3

Sample Output

1

题意:有N个人排成一行,每个人有不同的等级,两个人要决斗的话就要找一个裁判,裁判的等级要在他们之间,而且裁判也要站在他们之间。问一共能组成多少个不同的比赛。

思路:举个例子(等级不一定是1~N)

1 3 7 6 9 8 5

如果6是裁判,那左边等级比他低的人数(顺序数)a= 2;右边等级比他高的人数(顺序数)b = 2;左边等级比他高的人数(逆序数)c= 1;右边等级比他低的人数(逆序数)d = 1;

所以6做裁判的话就能组成a*b + c*d = 5个不同的比赛。

从左到右for一遍,把每个人做裁判能组成的比赛数目加起来就是结果。

逆序数与顺序数的求解可用树状数组

具体实现代码:

#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<map>
#include<queue>
#include<stack>
#include<vector>
#include<algorithm>
#include<cstring>
#include<string>
#include<iostream>
const int MAXN=20000+10;
using namespace std;
int a[MAXN];
int highl[MAXN];//highl[i]表示第i个数左边比a[i]大的数的个数
int highr[MAXN];//highr[i]表示第i个数右边比a[i]大的数的个数
int lowl[MAXN];//lowl[i]表示第i个数左边比a[i]小的数的个数
int lowr[MAXN];//lowr[i]表示第i个数右边比a[i]小的数的个数
int c[MAXN*5];

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

void update(int x, int num)
{
	while(x <= 5*MAXN-2)
	{
		c[x] += num;
		x += lowbit(x);
	}
}

int sum(int x)
{
	int res = 0;
	while(x > 0)
	{
		res += c[x];
		x -= lowbit(x);
	}
	return res;
}

int main()
{
	//freopen("in.txt","r",stdin);
	int T;
	scanf("%d", &T);
	while(T--)
	{
		int n;
		memset(c,0,sizeof(c));
		scanf("%d", &n);
		for(int i=0; i<n; i++){
			scanf("%d", a+i);
			int x = a[i];
			highl[i] = sum(5*MAXN) - sum(x);
			lowl[i] = sum(x);
			update(x,1);
		}
		memset(c,0,sizeof(c));
		for(int i=n-1; i>=0; i--){
			int x = a[i];
			highr[i] = sum(5*MAXN) - sum(x);
			lowr[i] = sum(x);
			update(x,1);
		}
		long long Sum = 0;
		for(int i=0; i<n; i++){//乘法原理和加法原理
			Sum += (long long) highl[i] * lowr[i];
			Sum += (long long) lowl[i] * highr[i];
		}
		printf("%lld\n", Sum);
	}
	return 0;
}
时间: 2024-07-31 20:29:50

树状数组+逆序数与顺序数——HDU 2492的相关文章

HDU 4911 (树状数组+逆序数)

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4911 题目大意:最多可以交换K次,就最小逆序对数 解题思路: 逆序数定理,当逆序对数大于0时,若ak<ak+1,那么交换后逆序对数+1,反之-1. 设原始序列最小逆序对数=cnt 那么,交换K次的最小逆序对数max(0,cnt-k) 在求原始序列最小逆序对数上,朴素暴力复杂度O(n^2)不可取 有以下两种O(nlogn)的方法: ①排序内计算: 主要是利用归并排序内的特性,即相邻两个归并序列逆序情

hdu2838Cow Sorting(树状数组+逆序数)

题目链接:点击打开链接 题意描述:给定一个长度为100000的数组,每个元素范围在1~100000,且互不相同,交换其中的任意两个数需要花费的代价为两个数之和.问如何交换使数组有序,花费的代价最小? 解题思路: 1.显然我们知道,要使一个数组有序至少交换的次数(即必须要交换的次数)为数组中的逆序数 2.由于数组的长度比较大所以我们可以通过树状数组来统计结果 此处需要两个树状数组 第一个:记录小于等于某个值的元素的个数 第二个:记录小于等于某个值的元素的和 代码: #include <cstdio

HDU5196--DZY Loves Inversions 树状数组 逆序数

题意查询给定[L, R]区间内 逆序对数 ==k的子区间的个数. 我们只需要求出 子区间小于等于k的个数和小于等于k-1的个数,然后相减就得出答案了. 对于i(1≤i≤n),我们计算ri表示[i,ri]的逆序对数小于等于K,且ri的值最大.(ri对应代码中的cnt数组) 显然ri单调不降,我们可以通过用两个指针扫一遍,利用树状数组计算出r数组. 对于每个询问L,R,我们要计算的是∑i=LR[min(R,ri)−i+1] 由于ri具有单调性,那我们直接在上面二分即可,然后记一个前缀和(s数组).

POJ3067 树状数组+逆序数

设两线段为(x1,y1) ,(x2,y2), 若使两线段相交,需使x1<x2&&y1>y2||x1>x2&&y1<y2. 那么本题就变得很简单了,对东边点x从小到大排序,当x相等时对西边点y从小到大排序,每插入一条线段,就求一下逆序对数.总和即为答案. 代码如下: 1 #include <stdio.h> 2 #include <string.h> 3 #include <algorithm> 4 #define

hdu 5193 分块 树状数组 逆序对

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

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这几个元素相邻的情况下,因为最后排列不存在逆序对,根据贪

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),表示字符串的长度

题解 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

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

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