[BZOJ]4430: [Nwerc2015]Guessing Camels赌骆驼 树状数组(思路好题)

Description

Jaap, Jan, and Thijs are on a trip to the desert after having attended the ACM ICPC World Finals 2015 in Morocco. The trip included a camel ride, and after returning from the ride, their guide invited them to a big camel race in the evening. The camels they rode will also participate and it is customary to bet on the results of the race.
One of the most interesting bets involves guessing the complete order in which the camels will finish the race. This bet offers the biggest return on your money, since it is also the one that is the hardest to get right.
Jaap, Jan, and Thijs have already placed their bets, but the race will not start until an hour from now, so they are getting bored. They started wondering how many pairs of camels they have put in the same order. If camel cc is before camel d on Jaap’s, Jan’s and Thijs’ bet, it means that all three of them put c and d in the same order. Can you help them to calculate the number of pairs of camels for which this happened?
Jaap,Jan和Thijs在摩洛哥参加完ACMICPC2015全球总决赛后去沙漠进行了一次旅行。旅行包括了骑骆驼。在骑完回来之后,他们的向导邀请他们在晚上去看一场盛大的骆驼赛跑。他们骑的骆驼也会参加,而赌比赛的结果是一个习惯。其中一个最有趣的赌涉及猜测完成比赛的骆驼的完整名单。这个赌可以为你赢得最多的钱,因为它也是最难猜对的。
Jaap,Jan和Thijs已经下了注,但比赛要在一个小时后才开始,所以他们觉得很无聊。他们开始想知道有多少对骆驼他们赌了同样的顺序。如果在他们三人的猜测名单中,骆驼c在骆驼d前,就意味着c和d在他们的名单中有相同的顺序。你能帮他们计算有多少对骆驼是这样的吗?

题解:

今天考试羊老师给我们出了这道题……虽然我知道这道题可以用cdq分治或树套树,然而我两个都不会……正解真的挺厉害的……考虑一个数对 (a,b) ,若不满足条件,那么在三个序列中,一定有两对 (a,b) ,一对 (b,a) ,或者两对 (b,a) ,一对 (a,b) ,那么可以看做是两对逆序对,也就是说三个序列两两找逆序对,逆序对数的一半就是不满足的情况,用总数减去就好了。

代码:

#include
using namespace std;
#define LL long long
#define pa pair
const int Maxn=200010;
const int inf=2147483647;
int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    return x*f;
}
int s[Maxn],n,a[3][Maxn];
void add(int x,int y){for(;x<=n;x+=(x&-x))s[x]+=y;}
int getsum(int x){int re=0;for(;x;x-=(x&-x))re+=s[x];return re;}
LL ans=0;
int pos[Maxn];
void work(int A,int B)
{
    memset(s,0,sizeof(s));
    for(int i=1;i<=n;i++)pos[a[A][i]]=i;
    for(int i=n;i;i--)
    {
        ans+=getsum(pos[a[B][i]]);
        add(pos[a[B][i]],1);
    }
}
int main()
{
    n=read();
    for(int i=0;i<3;i++)
    for(int j=1;j<=n;j++)
    a[i][j]=read();
    work(0,1);work(0,2);work(1,2);
    printf("%lld",(LL)(n)*(LL)(n-1)/2LL-ans/2LL);
}

你可能感兴趣的:(树状数组)