NC13947 contest(CDQ分治+樹狀數組+三維偏序)

題目鏈接

題意:
nn支隊伍,每支參加了三場比賽
xy如果三場比賽裏至少一場x隊比y隊排名高
xy那麼x隊自認爲比y強
(x,y)問有多少組(x,y)
xyyxx自認爲比y強,y自認爲比x強
xyyx(x,y)和(y,x)算同一組
題解:
i+1i首先對第一場排名進行排序,保證i+1自認爲比i強
j(1<=j<i)i然後就需要找有多少隊j(1<=j<i)後兩場比i強
n2這樣明顯一看是一個n^2算法
n<=2e5n2但是n<=2e5,肯定是不允許n^2

那換一個想法,反着寫
n(n1)/2總共有n*(n-1)/2種組合,有多少種組合不可能
減去之後就是答案
不可能的組一定是其中一組三場比賽都比另一組排名高
所以想找到不可能的組合
j(1<=j<i)i就是找多少隊j(1<=j<i)三場比賽比i排名都低
這樣問題就很明顯了,是一個裸的三維偏序問題
三個維分別代表三場比賽
cdqBIT三維偏序問題需要用cdq處理第二維,BIT處理第三維
首先對第一維進行從小到大排序,保證了第一維的有序
cdqBIT然後就行cdq分治,同時用BIT進行維護左區間第三維對應位置的個數
用兩個指針分別看左右區間的當前位
由於保證了左區間的第一維一定比右區間的第一維小
BIT如果左區間的當前位第二維小,把這一位的第三維加入BIT
BIT否則可以直接通過BIT統計當前有多少數比右區間這一位的第三維小
並加入答案,然後把歸併的順序賦給原數組,往上傳遞
(CDQ)(講的不是很清楚,可以到網上查閱CDQ分治或者三維偏序的講解,那裏會有更具體的解法)

AC代碼

/*
    Author:zzugzx
    Lang:C++
    Blog:blog.csdn.net/qq_43756519
*/
#include<bits/stdc++.h>
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;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章