ABC 306 F 题解

发布时间 2023-08-11 16:17:40作者: MrcFrst_LRY

原题传送门


题意:给定n个序列,每个序列有m个数。且这n * m个数互不相同。

定义f(A,B):将A、B两个数组合在一起升序排列后,记为数组C。
则f(A,B)为A数组中所有数在C数组中的下标之和。
求对于所有1<=i<j<=n,f(i,j)的和。


性质:可以大胆地排序,因为它只关心相对位置

硬算显然T飞,考虑批量计算贡献。

再看i和j的限制,十分灵性啊,一眼:倒着搞,就可以对于每一个i,把大于它的j都算进去,且只需要搞一遍。

每次只不过是查询一下排名罢了,随便选个ds就行了,比如优美的树状数组。当然我懒,直接复制了自己以前写的Treap板子(别学我

但是要注意,对于每个数在计算贡献的时候还要加上它之后(也就是此时ds里面已经维护了的(不包含当前数组))数组的数量,这个简单地打个草稿就能理解。

然后就结束了(你看这场的F是不是很水

还是贴个码,

#include<bits/stdc++.h>
using namespace std;
#define re  
#define int long long
const int N=10010,M=110;
const int INF=1e10;
int idx,root;
int n,m,a[N][M],ans;
struct node{
	int l,r;
	int key,val;
	int cnt,size;
}tr[N*M];
int get_node(int key){
	tr[++idx].key=key;
	tr[idx].val=rand();
	tr[idx].cnt=1;
	tr[idx].size=1;
	return idx;
}
void push_up(int id){
	tr[id].size=tr[tr[id].l].size+tr[tr[id].r].size+tr[id].cnt;
}
void build(){
	root=get_node(-INF),tr[1].r=get_node(INF);
	push_up(root);
}
void zig(int &p){
	int q=tr[p].r;
	tr[p].r=tr[q].l;
	tr[q].l=p;
	p=q;
	push_up(tr[p].l);
	push_up(p);
}
void zag(int &p){
	int q=tr[p].l;
	tr[p].l=tr[q].r;
	tr[q].r=p;
	p=q;
	push_up(tr[p].r);
	push_up(p);
}
void insert(int x,int &p){
	if(!p){
		p=get_node(x);
		return;
	}
	if(tr[p].key==x)tr[p].cnt++;
	else{
		if(x<tr[p].key){
			insert(x,tr[p].l);
			if(tr[tr[p].l].val>tr[p].val)zag(p);
		}
		else{
			insert(x,tr[p].r);
			if(tr[tr[p].r].val>tr[p].val)zig(p);
		}
	}
	push_up(p);
}
int get_rank(int x,int p){
	if(!p)return 0;
	if(tr[p].key==x)return tr[tr[p].l].size+1;
	if(x<tr[p].key)return get_rank(x,tr[p].l);
	return tr[tr[p].l].size+tr[p].cnt+get_rank(x,tr[p].r);
}
inline int read(){
    re int x=0,f=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return x*f;
}
signed main(){
	build();
	n=read(),m=read();
	for(re int i=1;i<=n;i++)for(re int j=1;j<=m;j++)a[i][j]=read();
	for(re int i=1;i<=m;i++)insert(a[n][i],root);
	for(re int i=n-1;i;i--){
		sort(a[i]+1,a[i]+1+m);
		for(re int j=1;j<=m;j++){
			int g=get_rank(a[i][j],root)-1;
			ans+=g+(n-i)*j;
		}
		for(re int j=1;j<=m;j++)insert(a[i][j],root);
	}
	printf("%lld",ans);
	return 0;
}