【bzoj4994】[Usaco2017 Feb]Why Did the Cow Cross the Road III 树状数组

题目描述

给定长度为2N的序列,1~N各处现过2次,i第一次出现位置记为ai,第二次记为bi,求满足ai<aj<bi<bj的对数

样例输入

4
3
2
4
4
1
3
2
1

样例输出

3



题解

树状数组

WH说是CDQ分治直接把我整蒙了。。。

把所有数按照第一次出现位置从小到大排序,然后扫一遍。此时一定是满足$a_j>a_i$的。

那么只需要求出$(a_j,b_j)$中以前出现过的$b_i$的数目。使用树状数组维护即可。

时间复杂度$O(n\log n)$

#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 50010
using namespace std;
struct data
{
	int a , b;
	bool operator<(const data &x)const {return a < x.a;}
}v[N];
int n , f[N << 1];
inline void add(int x)
{
	int i;
	for(i = x ; i <= n << 1 ; i += i & -i) f[i] ++ ;
}
inline int query(int x)
{
	int i , ans = 0;
	for(i = x ; i ; i -= i & -i) ans += f[i];
	return ans;
}
int main()
{
	int i , x , ans = 0;
	scanf("%d" , &n);
	for(i = 1 ; i <= n << 1 ; i ++ )
	{
		scanf("%d" , &x);
		if(!v[x].a) v[x].a = i;
		else v[x].b = i;
	}
	sort(v + 1 , v + n + 1);
	for(i = 1 ; i <= n ; i ++ ) ans += query(v[i].b - 1) - query(v[i].a - 1) , add(v[i].b);
	printf("%d\n" , ans);
	return 0;
}
时间: 2024-10-10 04:47:09

【bzoj4994】[Usaco2017 Feb]Why Did the Cow Cross the Road III 树状数组的相关文章

BZOJ4994 [Usaco2017 Feb]Why Did the Cow Cross the Road III 树状数组

欢迎访问~原文出处--博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ4994 题意概括 给定长度为2N的序列,1~N各处现过2次,i第一次出现位置记为ai,第二次记为bi,求满足ai<aj<bi<bj的对数. n<=100000(这个数据范围是我凑出来的,但是我没试过更小的范围,BZOJ上没写数据范围(截止2017-08-24)) 题解 水题,开一个树状数组在线解决. 比如我们顺着扫过去,当到达一个 bj 时,我们求满足条件的 ai,bi 个数,其实就

[BZOJ4989] [Usaco2017 Feb]Why Did the Cow Cross the Road(树状数组)

传送门 发现就是逆序对 可以树状数组求出 对于旋转操作,把一个序列最后面一个数移到开头,假设另一个序列的这个数在位置x,那么对答案的贡献 - (n - x) + (x - 1) #include <cstdio> #include <cstring> #include <iostream> #define N 200011 #define LL long long using namespace std; int n; int a[N], b[N], pos1[N],

[BZOJ4994] [Usaco2017 Feb]Why Did the Cow Cross the Road III(树状数组)

传送门 1.每个数的左右位置预处理出来,按照左端点排序,因为左端点是从小到大的,我们只需要知道每条线段包含了多少个前面线段的右端点即可,可以用树状数组 2.如果 ai < bj < bi, 也就是说在两个i之间只有一个j那么对答案的贡献为1,所以可以用树状数组,当第一次出现一个数的时候,那个位置+1,当第二次出现的时候,第一次出现的位置再-1,也就是把它对答案的贡献去掉,同样是树状数组统计答案 #include <cstdio> #include <iostream>

BZOJ4989 [Usaco2017 Feb]Why Did the Cow Cross the Road 树状数组 逆序对

欢迎访问~原文出处--博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ4989 题意概括 一条马路的两边分别对应的序列A.B,长度为n,两序列为1到n的全排列.当Ai=Bj时,两边之间会连一条边.你可以选择序列A或序列B进行旋转(只能使队尾或队头位置上的数字变成队头或队尾上的数字)任意K(0<=K<n)步,如123,可以变成 231 或 312.求旋转后,最少的边的交叉数. 题解 两个都可以转,那么我们只需要分别转动两个并统计即可. 旋转一个,那么我们只需要统计逆序

Why Did the Cow Cross the Road III(树状数组)

Why Did the Cow Cross the Road III 时间限制: 1 Sec  内存限制: 128 MB提交: 65  解决: 28[提交][状态][讨论版] 题目描述 The layout of Farmer John's farm is quite peculiar, with a large circular road running around the perimeter of the main field on which his cows graze during

洛谷 P3660 [USACO17FEB]Why Did the Cow Cross the Road III G(树状数组)

题目背景 给定长度为2N的序列,1~N各处现过2次,i第一次出现位置记为ai,第二次记为bi,求满足ai<aj<bi<bj的对数 题目描述 The layout of Farmer John's farm is quite peculiar, with a large circular road running around the perimeter of the main field on which his cows graze during the day. Every morn

[Usaco2017 Feb]Why Did the Cow Cross the RoadII

[题目链接] https://www.lydsy.com/JudgeOnline/problem.php?id=4993 [算法] 动态规划 转移类似于求LCS [代码] #include<bits/stdc++.h> using namespace std; #define MAXN 1010 int n; int a[MAXN] , b[MAXN]; int f[MAXN][MAXN]; template <typename T> inline void chkmax(T &a

[USACO17FEB]Why Did the Cow Cross the Road III P(CDQ分治)

题意 两列$n$的排列,相同的数连边,如果一对数有交叉且差的绝对值$>k$,则$++ans$,求$ans$ 题解 可以把每一个数字看成一个三元组$(x,y,z)$,其中$x$表示在第一列的位置,$y$表示在第二列的位置,$z$表示权值 两条线交叉,就是$x<x'$且$y>y'$,又要满足差值的绝对值小于等于$k$,就是$|z-z'|<=k$ 于是就转化为了一个三维偏序问题,直接上CDQ 具体细节请看代码 1 // luogu-judger-enable-o2 2 //minamot

Why Did the Cow Cross the Road III HYSBZ - 4991 -CDQ-逆序数

HYSBZ - 4991 题意: 第一列 1-n的排列 ,第二列 1-n的排列.  相同数字连边  ,问  有多少组 数字 是有交点的并且 绝对值之差>K思路:处理一下 1-n 在第一列的位置,1-n在第二列的位置.按照第一列的位置从小到大排序,然后 进行cdq分治,因为现在第一列已经是递增序列了,如果在第二列中出现了递减那么这两个数就有交点,分治解决,递归左区间 的必然第一列必然小于递归右区间.所以只处理左区间对右区间的影响,两段小区间分别按照 b 从大到小排序,然后 统计 左区间的b  比右