NC13947 contest(CDQ分治+树状数组+三维偏序)

题目链接

题意:
n 支 队 伍 , 每 支 参 加 了 三 场 比 赛 n支队伍,每支参加了三场比赛 n
如 果 三 场 比 赛 里 至 少 一 场 x 队 比 y 队 排 名 高 如果三场比赛里至少一场x队比y队排名高 xy
那 么 x 队 自 认 为 比 y 强 那么x队自认为比y强 xy
问 有 多 少 组 ( x , y ) 问有多少组(x,y) (x,y)
x 自 认 为 比 y 强 , y 自 认 为 比 x 强 x自认为比y强,y自认为比x强 xyyx
( x , y ) 和 ( y , x ) 算 同 一 组 (x,y)和(y,x)算同一组 xyyx
题解:
首 先 对 第 一 场 排 名 进 行 排 序 , 保 证 i + 1 自 认 为 比 i 强 首先对第一场排名进行排序,保证i+1自认为比i强 i+1i
然 后 就 需 要 找 有 多 少 队 j ( 1 < = j < i ) 后 两 场 比 i 强 然后就需要找有多少队j(1<=jj(1<=j<i)i
这 样 明 显 一 看 是 一 个 n 2 算 法 这样明显一看是一个n^2算法 n2
但 是 n < = 2 e 5 , 肯 定 是 不 允 许 n 2 但是n<=2e5,肯定是不允许n^2 n<=2e5n2

那 换 一 个 想 法 , 反 着 写 那换一个想法,反着写
总 共 有 n ∗ ( n − 1 ) / 2 种 组 合 , 有 多 少 种 组 合 不 可 能 总共有n*(n-1)/2种组合,有多少种组合不可能 n(n1)/2
减 去 之 后 就 是 答 案 减去之后就是答案
不 可 能 的 组 一 定 是 其 中 一 组 三 场 比 赛 都 比 另 一 组 排 名 高 不可能的组一定是其中一组三场比赛都比另一组排名高
所 以 想 找 到 不 可 能 的 组 合 所以想找到不可能的组合
就 是 找 多 少 队 j ( 1 < = j < i ) 三 场 比 赛 比 i 排 名 都 低 就是找多少队j(1<=jj(1<=j<i)i
这 样 问 题 就 很 明 显 了 , 是 一 个 裸 的 三 维 偏 序 问 题 这样问题就很明显了,是一个裸的三维偏序问题
三 个 维 分 别 代 表 三 场 比 赛 三个维分别代表三场比赛
三 维 偏 序 问 题 需 要 用 c d q 处 理 第 二 维 , B I T 处 理 第 三 维 三维偏序问题需要用cdq处理第二维,BIT处理第三维 cdqBIT
首 先 对 第 一 维 进 行 从 小 到 大 排 序 , 保 证 了 第 一 维 的 有 序 首先对第一维进行从小到大排序,保证了第一维的有序
然 后 就 行 c d q 分 治 , 同 时 用 B I T 进 行 维 护 左 区 间 第 三 维 对 应 位 置 的 个 数 然后就行cdq分治,同时用BIT进行维护左区间第三维对应位置的个数 cdqBIT
用 两 个 指 针 分 别 看 左 右 区 间 的 当 前 位 用两个指针分别看左右区间的当前位
由 于 保 证 了 左 区 间 的 第 一 维 一 定 比 右 区 间 的 第 一 维 小 由于保证了左区间的第一维一定比右区间的第一维小
如 果 左 区 间 的 当 前 位 第 二 维 小 , 把 这 一 位 的 第 三 维 加 入 B I T 如果左区间的当前位第二维小,把这一位的第三维加入BIT BIT
否 则 可 以 直 接 通 过 B I T 统 计 当 前 有 多 少 数 比 右 区 间 这 一 位 的 第 三 维 小 否则可以直接通过BIT统计当前有多少数比右区间这一位的第三维小 BIT
并 加 入 答 案 , 然 后 把 归 并 的 顺 序 赋 给 原 数 组 , 往 上 传 递 并加入答案,然后把归并的顺序赋给原数组,往上传递
( 讲 的 不 是 很 清 楚 , 可 以 到 网 上 查 阅 C D Q 分 治 或 者 三 维 偏 序 的 讲 解 , 那 里 会 有 更 具 体 的 解 法 ) (讲的不是很清楚,可以到网上查阅CDQ分治或者三维偏序的讲解,那里会有更具体的解法) (CDQ)

AC代码

/*
    Author:zzugzx
    Lang:C++
    Blog:blog.csdn.net/qq_43756519
*/
#include
using namespace std;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define endl '\n'
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
//const int mod=1e9+7;
const int mod=998244353;
const double eps = 1e-10;
const double pi=acos(-1.0);
const int maxn=1e6+10;
const ll inf=0x3f3f3f3f;
const int dir[4][2]={{0,1},{1,0},{0,-1},{-1,0}};

ll n,ans,c[maxn];
struct node{
    ll a,b,c;
}p[maxn],p1[maxn];
bool cmp(node a,node b){
    return a.a<b.a;
}
int lowbit(int x){
    return x&(-x);
}
void add(int x,ll v){
    while(x<maxn){
        c[x]+=v;
        x+=lowbit(x);
    }
}
ll query(int x){
    ll res=0;
    while(x){
        res+=c[x];
        x-=lowbit(x);
    }
    return res;
}
void cdq(int l,int r){
    if(l==r)return;
    int mid=l+r>>1;
    cdq(l,mid);cdq(mid+1,r);
    int i=l,j=mid+1,k=l;
    while(i<=mid&&j<=r){
        if(p[i].b<p[j].b)add(p[i].c,1),p1[k++]=p[i++];
        else ans+=query(p[j].c),p1[k++]=p[j++];
    }
    while(i<=mid)add(p[i].c,1),p1[k++]=p[i++];
    while(j<=r)ans+=query(p[j].c),p1[k++]=p[j++];
    for(int i=l;i<=mid;i++)add(p[i].c,-1);
    for(int i=l;i<=r;i++)p[i]=p1[i];
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    cin>>n;
    for(int i=1;i<=n;i++)cin>>p[i].a>>p[i].b>>p[i].c;
    sort(p+1,p+1+n,cmp);
    cdq(1,n);
    cout<<n*(n-1)/2-ans;
    return 0;
}

你可能感兴趣的:(NC13947 contest(CDQ分治+树状数组+三维偏序))