Problem:
n支队伍一共参加了三场比赛。
一支队伍x认为自己比另一支队伍y强当且仅当x在至少一场比赛中比y的排名高。
求有多少组(x,y),使得x自己觉得比y强,y自己也觉得比x强。
(x, y), (y, x)算一组。
Solution:
使得x自己觉得比y强,y自己也觉得比x强,即对于x和y来说,在3场比赛中存在x的排名大于y,y的排名大于x。
在题目中每个人有3场比赛的排名,若我们将第一场比赛排名按从大到小排序后,然后遍历的时候从头遍历,
这样其实就已经消除了一场比赛的影响,只需要考虑剩下的第二场比赛了,其实有经验的人可以看出这题题目和偏序有关,
( 一维偏序就是不需要处理,直接求逆序对
二维偏序就是将第一维排序后再求第二维的逆序对数
三维偏序就是 一维排序,二维分治,三维树状数组 -- 》 cdq分治
)
由于题目中给出了问题是求解有多少对(x,y)满足在3场比赛中存在x的排名大于y,y的排名大于x,所以我们用二维偏序即可解决,
对于能够满足需要的(x,y)来说,有这三种比赛结果满足(第一场(x1>y1),第二场(x2<y2))(第一场(x1>y1),第三场(x3<y3))(第二场(x2>y2),第三场(x3<y3))
由于上面只要有一种情况出现,那么一定就会出现两种(因为排名不会出现同样的。若x1>y1 & x2<y2,那么一定会出现((x1>y1) & (x3<y3) 和(x2>y2)&(x3<y3)中其中一种,其它的同理)
首先一维排好序后,求(二维的逆序对数 + 三维的逆序对数)
然后二维排好序后,求(三维的逆序对数)
最终将结果/2就是答案
tip:
对于题目的求解,当有2个不确定问题时,我们应该看是否能固定一个问题,然后使其只剩下一个待解决的问题 ,有可能只有一个需要解决时,它会变成你熟悉的问题。
#include<bits/stdc++.h> #define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0) #define _for(i,s,t) for(int i=s;i<t;i++) #define _rof(i,s,t) for(int i=s;i>t;i--) #define rep(i,s,t) for(int i=s;i<=t;i++) #define per(i,s,t) for(int i=s;i>=t;i--) #define Ri(x) scanf("%d",&x) #define Rii(x,y) scanf("%d%d",&x,&y) #define INF 0x3f3f3f3f using namespace std; template<class T>inline void read(T &res) { char c;T flag=1; while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;res=c-'0'; while((c=getchar())>='0'&&c<='9')res=res*10+c-'0';res*=flag; } typedef long long ll; const int maxn = 2e5 + 10; int n,c[maxn]; struct Node{ int a,b,c; }nd[maxn]; bool cmp1(Node nd1,Node nd2){ return nd1.a > nd2.a; } bool cmp2(Node nd1,Node nd2){ return nd1.b > nd2.b; } int lowbit(int x){ return x & (-x); } void add(int i,int v){ while(i <= n){ c[i] += v; i += lowbit(i); } } ll query(int i){ ll result = 0; while(i > 0){ result += c[i]; i -= lowbit(i); } return result; } int main(){ IOS; cin>>n; rep(i,1,n){ cin>>nd[i].a>>nd[i].b>>nd[i].c; } sort(nd + 1,nd + 1 + n,cmp1); ll ans = 0; rep(i,1,n){ ans += query(nd[i].b); add(nd[i].b,1); } memset(c,0,sizeof(c)); rep(i,1,n){ ans += query(nd[i].c); add(nd[i].c,1); } sort(nd + 1,nd + 1 + n,cmp2); memset(c,0,sizeof(c)); rep(i,1,n){ ans += query(nd[i].c); add(nd[i].c,1); } cout<<ans/2<<endl; return 0; } /** Problem: n支队伍一共参加了三场比赛。 一支队伍x认为自己比另一支队伍y强当且仅当x在至少一场比赛中比y的排名高。 求有多少组(x,y),使得x自己觉得比y强,y自己也觉得比x强。 (x, y), (y, x)算一组。 Solution: 使得x自己觉得比y强,y自己也觉得比x强,即对于x和y来说,在3场比赛中存在x的排名大于y,y的排名大于x。 在题目中每个人有3场比赛的排名,若我们将第一场比赛排名按从大到小排序后,然后遍历的时候从头遍历, 这样其实就已经消除了一场比赛的影响,只需要考虑剩下的第二场比赛了,其实有经验的人可以看出这题题目和偏序有关, ( 一维偏序就是不需要处理,直接求逆序对 二维偏序就是将第一维排序后再求第二维的逆序对数 三维偏序就是 一维排序,二维分治,三维树状数组 -- 》 cdq分治 ) 由于题目中给出了问题是求解有多少对(x,y)满足在3场比赛中存在x的排名大于y,y的排名大于x,所以我们用二维偏序即可解决, 对于能够满足需要的(x,y)来说,有这三种比赛结果满足(第一场(x1>y1),第二场(x2<y2))(第一场(x1>y1),第三场(x3<y3))(第二场(x2>y2),第三场(x3<y3)) 由于上面只要有一种情况出现,那么一定就会出现两种(因为排名不会出现同样的。若x1>y1 & x2<y2,那么一定会出现((x1>y1) & (x3<y3) 和(x2>y2)&(x3<y3)中其中一种,其它的同理) 首先一维排好序后,求(二维的逆序对数 + 三维的逆序对数) 然后二维排好序后,求(三维的逆序对数) 最终将结果/2就是答案 tip:对于题目的求解,当有2个不确定问题时,我们应该看是否能固定一个问题,然后使其只剩下一个待解决的问题 ,有可能只有一个需要解决时,它会变成你熟悉的问题。 */