首页 > 其他分享 >P10149 [Ynoi1999] XM66F题解

P10149 [Ynoi1999] XM66F题解

时间:2024-02-16 19:33:31浏览次数:21  
标签:cnt limits int 题解 sum XM66F s2 P10149 s1

image

题解

首先,问题是静态的区间查询问题,一眼莫队。那么我们就需要考虑所需要维护的内容在区间扩增或者缩减时的变化如何快速维护。我们可以先写出对于区间 \([l,r]\) 来说,满足 \(l \le i < j < k \le r\) 的有序三元组 \((i,j,k)\) 数量的表达式,方便拆式子:

\[\sum\limits_{i = l}^{r} {\sum\limits_{j = l}^{i-1}{[a_j=a_i]\sum\limits_{k = j+1}^{i-1}{[a_k<a_i]}}} \]

记作形式 1。或者:

\[\sum\limits_{i = l}^{r} {\sum\limits_{j = i+1}^{r}{[a_j=a_i]\sum\limits_{k = i+1}^{j-1}{[a_k<a_i]}}} \]

记作形式 2,上述括号均为艾弗森括号。

接下来我们分别考虑 \([l,r]\) 扩增为 \([l,r+1]\) 和 \([l-1,r]\) 的情况,至于缩减,作为扩增的逆操作是同理的,先看右端点右移,运用形式 1,增量为:

\[\sum\limits_{j = l}^{r}{[a_j=a_{r+1}]\sum\limits_{k = j+1}^{r}{[a_k<a_{r+1}]}} \]

注意到后面的求和式实际上是一个二维偏序,我们按照前缀和的思路记:

\[cnt_i=\sum\limits_{j=1}^{i}{[a_j<a_i]} \]

显然可以用树状数组做到 \(O(n\log n)\) 的预处理。那么原来的增量就能写成:

\[cnt_{r+1}\sum\limits_{j = l}^{r}{[a_j=a_{r+1}]}-\sum\limits_{j = l}^{r}{cnt_j[a_j=a_{r+1}]} \]

这下就很显然了,我们动态维护两个桶 \(s_1\),\(s_2\),其中下标为 \(a_{r+1}\) 时 \(s_1=\sum\limits_{j = l}^{r}{[a_j=a_{r+1}]}\),\(s_2=\sum\limits_{j = l}^{r}{cnt_j[a_j=a_{r+1}]}\)。扩增后,只需要对该下标的 \(s_1\) 增加 1,\(s2\) 增加 \(cnt_{r+1}\),转移是 \(O(1)\) 的。

对于左端点左移,我们运用形式 2,和刚才一样的方法,增量可以写成:

\[-cnt_{l-1}\sum\limits_{j = l}^{r}{[a_j=a_{l-1}]}+\sum\limits_{j = l}^{r}{cnt_j[a_j=a_{l-1}]} \]

形式一点没变,但是系数变为原来的相反数,这不影响统计,我们仍然可以按照刚才的维护方法进行左端点左移,不过我们可能要特殊判断一下增量的系数。

但也不必,显然区间扩增后,增量一定是非负数,那么我们可以认为左端点左移的增量式子是其相反数的绝对值,而右端点右移的增量式子是其本身的绝对值,这样形式和系数都统一了,不需要特判,代码实现比较工整。

由于可以 \(O(1)\) 转移,复杂度为 \(O(n\sqrt n)\),加上奇偶排序的话常数就不是很大了,可以通过本题。

AC code

#include<bits/stdc++.h>
#define int long long 
using namespace std;
const int N=5e5+10;
int n,m,a[N],l,r,cnt[N],s1[N],s2[N]; 
int B,ans[N],now;
struct Query {
	int l,r,id,bel;
}q[N];
struct BST {
	int c[N]; 
	int lowbit(int x) {
		return x&-x;
	}
	void update(int x,int y) {
		for(;x<=n;x+=lowbit(x)) c[x]+=y;
	}
	int sum(int x) {
		int ans=0;
		while(x>0) {
			ans+=c[x];
			x-=lowbit(x);
		}
		return ans;
	}
}T;
bool cmp(Query x,Query y) {
	if(x.bel!=y.bel) return x.bel<y.bel;
	if(x.bel&1) return x.r<y.r;
	else return x.r>y.r;
}
void add(int i) {
	now+=abs(cnt[i]*s1[a[i]]-s2[a[i]]);
	s1[a[i]]++;
	s2[a[i]]+=cnt[i];
}
void del(int i) {
	s1[a[i]]--;
	s2[a[i]]-=cnt[i];
	now-=abs(cnt[i]*s1[a[i]]-s2[a[i]]);
}
signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	cin>>n>>m;
	B=(int)(n*1.0/sqrt(m));
	for(int i=1;i<=n;i++) cin>>a[i];
	for(int i=1;i<=n;i++) {
		T.update(a[i],1);
		cnt[i]=T.sum(a[i]-1);
	}
	for(int i=1;i<=m;i++) {
		cin>>l>>r;
		q[i]={l,r,i,(l-1)/B+1};
	}
	sort(q+1,q+m+1,cmp);
	l=1,r=1;
	s1[a[1]]++;
	s2[a[1]]+=cnt[1]; 
	for(int i=1;i<=m;i++) {
		while(l>q[i].l) add(--l);
		while(r<q[i].r) add(++r);
		while(l<q[i].l) del(l++);
		while(r>q[i].r) del(r--);
		ans[q[i].id]=now;
	}
	for(int i=1;i<=m;i++) cout<<ans[i]<<endl;
	return 0;
}

标签:cnt,limits,int,题解,sum,XM66F,s2,P10149,s1
From: https://www.cnblogs.com/2021hych/p/18017402

相关文章

  • 启动vue-element-admin遇到问题解决方案
    概述从https://github.com/PanJiaChen/vue-element-admin下载代码,按照文档执行,期间遇到一些列问题。1#clonetheproject2gitclonehttps://github.com/PanJiaChen/vue-element-admin.git34#entertheprojectdirectory5cdvue-element-admin67#insta......
  • 出现8080端口占用问题解决
    查到占用端口号并关闭netstat-aon|findstr8080出现:TCP0.0.0.0:80000.0.0.0:0LISTENING23296TCP[::]:8000[::]:0LISTENING23296tasklist|findstr"23296"出现:java.exe......
  • CF739A Alyona and mex 题解
    题目简单构造,首先我们知道一个区间\([l,r]\)内的最大答案为为这个区间的长度\(len\),因为其中可以包括\([0,r-l+1]\)这些数。所以\(ans=min(len_i)\)。考虑如何满足这个条件,设最小长度为\(len_{min}\),我们可以轮流输出\([0,len_{min}]\),因为\(len_{min}\)是最小长度,所......
  • 树状数组-三色二叉树 题解
    题目在这里————————————————————————————————三色二叉树首先题面写的很清楚了是一道树状数组题因为这题的输入方式很特别按二叉树序列所以在输入上要特殊处理如下voidread(intx){//读入+存图以左右子树为形式如l[x]=y即y为x左子树......
  • [Vijos P1448] 校门外的树 题解
    题目描述校门外有很多树,学校决定在某个时刻在某一段种上一种树,保证任一时刻不会出现两段相同种类的树,现有两种操作:k==1,读入l,r表示在l到r之间种上一种树,每次操作种的树的种类都不同;k==2,读入l,r表示询问l到r之间有多少种树。注意:每个位置都可以重复种树。......
  • CF55D Beautiful numbers 题解
    题目链接:CF或者洛谷常见知识点组合经典题。首先,一眼数位dp类型题,考虑需要处理些怎样的判断合法数位信息。经典操作对于跟整除有关的判断,数位dp为了减少使用空间,都可以考虑记忆化模数减少空间开销。对于整除若干个数,即整除这若干个数的最小公倍数即可,是一个非常常用......
  • 【题解】P4722 【模板】最大流 加强版 / 预流推进
    更好阅读体验CHAPTER0废话1.常见的最大流算法可以大致分为两种:找增广路和预流推进2.从理论时间复杂度上界来看,找增广路算法的最坏时间复杂度为\(O(n^2m)\),而预流推进算法的最坏时间复杂度为\(O(n^2\sqrt{m})\),看起来预流推进要显然优于找增广路,但在实际应用(尤指OI)中,由于包......
  • HDU-Employment Planning题解
    题目在这里————————————————————————————————EmploymentPlanning简单的一道dp关键的点在于想到用枚举实现各种情况的讨论关键的注释写在代码里了还是很清晰的捏~#include<bits/stdc++.h>#definefo(x,y,z)for(int(x)=(y);(x)<=(z);(x......
  • 题解 LGP10144【[WC/CTS2024] 水镜】
    题解P10144【[WC/CTS2024]水镜】题目描述给定一个长度为\(n\)的正整数序列\(h_1,h_2,\cdots,h_n\),求满足以下所有条件的二元组\((u,v)\)的数量:\(1\leu<v\len\),且\(u,v\)为整数;存在一个正实数\(L\)以及一个长度为\((v-u+1)\)的序列\(r_u,r_{u+......
  • Codeforces Round 926 (Div. 2) 题解
    比赛链接:https://codeforces.com/contest/1929官解链接:https://codeforces.com/blog/entry/125943出的很差的一场。推歌CF1929A.SashaandtheBeautifulArray题意任意排列数组\(a_{1..n}\),求\(\sum_{i=2}^n(a_i-a_{i-1})\)的最大值。题解见过最显然的A题,奠定了......