首页 > 其他分享 >洛谷 P3157 [CQOI2011]动态逆序对

洛谷 P3157 [CQOI2011]动态逆序对

时间:2022-08-17 12:16:59浏览次数:61  
标签:洛谷 P3157 删除 int mid pos include CQOI2011 逆序

Description

对于序列 \(a\),它的逆序对数定义为集合

\[\{(i,j)| i<j \and a_i > a_j \} \]

中的元素个数。

现在给出 \(1\sim n\) 的一个排列,按照某种顺序依次删除 \(m\) 个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数。

Solution

发现 \(a_{i}\) 很大,肯定先离散化后处理。

可以先求出所有的逆序对,在每次删除数之后就减去这个数对逆序对的贡献。

我们再给每个要删掉的数一个删除时间,若这个数没有被删除,那么就把删除时间设置为 INF。

贡献如何计算?

  • 位置在这个数前面,数值比该数,且删除时间比它的数。

  • 位置在这个数后面,数值比该数,且删除时间比它的数。

我们要找的都是删除时间比它晚的数,否则即使能产生逆序对,也因为更早被删除而计入更早那个数的贡献,不能重复计数。

现在这个问题就转化成了静态三维数点(三位偏序)的问题,且可以离线,考虑用 CDQ 分治做。

先按照时间的从晚到早的顺序排序,去掉了一维,然后不断递归,分成左右区间,每次递归完成后计算左右区间跨区间的贡献即可。

注意这里要计算两次贡献,每一次贡献计算完毕后应当清空树状数组。

Code

// by youyou2007 in 2022.
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <queue>
#include <stack>
#include <map>
#define REP(i, x, y) for(int i = x; i < y; i++)
#define rep(i, x, y) for(int i = x; i <= y; i++)
#define PER(i, x, y) for(int i = x; i > y; i--)
#define per(i, x, y) for(int i = x; i >= y; i--)
#define lc (k << 1)
#define rc (k << 1 | 1)
using namespace std;
/*
inline int read()
{
    int s = 0, w = 1; char ch = getchar();
    while(ch < '0' || ch > '9'){ if(ch == '-') w = -1; ch = getchar();}
    while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
    return s * w;
}
*/
const int N = 100005;
struct node{
	int t, pos, val;
    long long ans;
}a[N];
int n, m, tree[N], del[N], id[N];
bool cmp1(node x, node y)//外层排序,按照时间排序
{
	if(x.t != y.t) return x.t > y.t;
	return x.pos < y.pos;
}
bool cmp2(node x, node y)//内层排序,按照位置排序
{
	return x.pos < y.pos;
}
int lowbit(int x)
{
	return x & (-x);
}
void add(int x, int y)
{
	while(x <= n)
	{
		tree[x] += y;
		x += lowbit(x);
	}
}
int query(int x)
{
	int res = 0;
	while(x > 0)
	{
		res += tree[x];
		x -= lowbit(x);
	}
	return res;
}
void CDQ(int l, int r)
{
	if(l == r) return;
	int mid = (l + r) / 2;
	CDQ(l, mid);
	CDQ(mid + 1, r);
	sort(a + l, a + mid + 1, cmp2);
	sort(a + mid + 1, a + r + 1, cmp2);
	int j = l;
	for(int i = mid + 1; i <= r; i++)//计算比该数大且位置更靠前的数的个数 
	{
		while(j <= mid && a[i].pos >= a[j].pos)
		{
			add(a[j].val, 1);
			j++;
		}
		a[i].ans += query(n) - query(a[i].val);
	}
	for(int i = l; i <= j - 1; i++)//清空树状数组
	{
		add(a[i].val, -1);
	}
	j = mid;
	for(int i = r; i >= mid + 1; i--)//计算比该数小且位置更靠后的数的个数
	{
		while(j >= l && a[i].pos <= a[j].pos)
		{
			add(a[j].val, 1);
			j--;
		}
		a[i].ans += query(a[i].val - 1);
	}
	for(int i = mid; i >= j + 1; i--)
	{
		add(a[i].val, -1);
	}
}
int main()
{
	scanf("%d%d", &n, &m);
	for(int i = 1; i <= n; i++)
	{
		scanf("%d", &a[i].val); 
		a[i].pos = i;
		a[i].t = n + 4;//若该数未被删除过,则随便定一个比较大的值
                id[a[i].val] = i;//记录下每个数原来的位置
	}
	for(int i = 1; i <= m; i++)
	{
		scanf("%d", &del[i]);
		a[id[del[i]]].t = i; 
	}
	long long now = 0;
	for(int i = 1; i <= n; i++)//先利用一次树状数组处理出初始逆序对数量
	{
		now += query(n) - query(a[i].val);
		add(a[i].val, 1);
	}
	for(int i = 1; i <= n; i++)
	{
		add(a[i].val, -1);
	}
	sort(a + 1, a + n + 1, cmp1);
	CDQ(1, n);
        sort(a + 1, a + n + 1, cmp2);//最后应当按照删除时间顺序再排一遍
	for(int i = 1; i <= m; i++)
	{
		printf("%lld\n", now);
		now -= a[id[del[i]]].ans;//注意题目要求,应当先输出再减	
        }
	return 0;
}

标签:洛谷,P3157,删除,int,mid,pos,include,CQOI2011,逆序
From: https://www.cnblogs.com/pjxpjx/p/16586703.html

相关文章

  • 洛谷P1972HH的项链 题解
    P1972[SDOI2009]HH的项链题目描述HH有一串由各种漂亮的贝壳组成的项链。HH相信不同的贝壳会带来好运,所以每次散步完后,他都会随意取出一段贝壳,思考它们所表达的含......
  • 洛谷 P6242 【模板】线段树 3 吉司机线段树 区间取最小值 维护历史最大值和区间和
    题目背景本题是线段树维护区间最值操作与区间历史最值的模板。题目描述给出一个长度为 nn 的数列 AA,同时定义一个辅助数组 BB,BB 开始与 AA 完全相同。接下来......
  • 洛谷 P3964 松鼠聚会
    前言由于未知原因,解密被取消了。其实就是我懒$\color{white}{恭喜你发现本彩蛋!Name:UR\next\\\Password:Zjd6MWpnMjZhNA==空格\to下划线}$正文题面有......
  • 洛谷P1714切蛋糕题解
    P1714切蛋糕题目描述今天是小Z的生日,同学们为他带来了一块蛋糕。这块蛋糕是一个长方体,被用不同色彩分成了\(n\)个相同的小块,每小块都有对应的幸运值。小Z作......
  • 洛谷P2622 关灯问题II引发的关于DP实现形式及后效性的思考
      动态规划要求已经求解的子问题不受后续阶段的影响,即无后效性。而在这种递推的实现方式中,后面枚举的状态可能更新前面已经枚举过的状态。也就是说,这种递推的实现方式是......
  • 洛谷 P1654 OSU!
    思路考虑\(DP\)转移,设\(F[i]\)表示长度为\(i\)序列的期望分数。得到如下转移:\(F[i]=(F[i-1]-A[i-1]+A[i])p_i+F[i-1](1-p_i)\)其中\(A[i]\)的意义是:以\(i\)......
  • 洛谷-P2486 染色
    染色树链剖分考虑如果在数列上的话,就是用线段树处理这个问题线段树记录答案,并且处理区间和并的问题:如果区间合并的地方颜色相同,则加和后的答案要减一因此维护所有线段......
  • 洛谷P6812「MCOI-02」Ancestor 先辈
    洛谷P6812对于题目的区间加法明显可以用线段树或树状数组进行并且由题可得,先辈序列即为不下降序列,需满足ai<aj&&i<j判断一个序列是否为先辈我们比较的是一个元素和前一......
  • 洛谷 P6789 - 寒妖王(子集卷积+矩阵树定理)
    洛谷题面传送门像极了我验的那道牛客多校(第六场CForest)……考虑对于每条边,计算其在最大生成基环森林中的概率,乘以边权求和就是答案。现在问题在于如何计算每条边在最大......
  • 8.14 洛谷月赛
    感觉没有tg难\(\rmLink\)目录\(T1\)\(T2\)\(T3\)(主打\(div2\))\(T1\)这个\(T1\)是个神仙题,我甚至为它写了一个\(45pts\)的暴力分然后过去切了\(T2\)再回来看才......