关于树状数组求非严格逆序对

P1908 逆序对

Cosine_Func @ 2024-10-19 17:44:28

严格逆序对排序部分:

struct Node{
    int v,id;
    bool operator<(const Node &b)const{
        return v<b.v;
        //小于
    }
}b[N];

非严格逆序对排序部分:

struct Node{
    int v,id;
    bool operator<(const Node &b)const{
        return v<=b.v;
        //小于等于
    }
}b[N];

完整代码:

#include<bits/stdc++.h>
#define pb push_back
#define ll long long
#define endl '\n'
#define itn int
#define pi pair<int,int>
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)<(y)?(x):(y))
#define int ll
using namespace std;
const int MOD1=1e9+7;
const int MOD2=998244353;
const int N=2e5+5;
struct Node{
    int v,id;
    bool operator<(const Node &b)const{
        return v<=b.v;
    }
}b[N];
int n,ans,a[N],t[N];
int lowbit(itn x){
    return x&(-x);
}
void add(itn x,itn k){
    for(int i=x;i<=n;i+=lowbit(i))
        t[i]+=k;
}
int ask(int x){
    int res=0;
    for(int i=x;i;i-=lowbit(i))
        res+=t[i];
    return res;
}
inline void Solve(){
    cin>>n;
    for(int i=1;i<=n;i++)
        cin>>b[i].v,b[i].id=i;
    stable_sort(b+1,b+n+1);
    for(int i=1;i<=n;i++)
        a[b[i].id]=i;
    for(int i=1;i<=n;i++){
        add(a[i],1);
        ans+=i-ask(a[i]);
    }
    cout<<ans;
}
signed main()
{
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    freopen("cross.in","r",stdin);
    freopen("cross.out","w",stdout);
    int T=1;
    //cin>>T;
    while(T--)
        Solve();
    return 0;
}

站外题 AC。求正确性证明 or hack


by Terrible @ 2024-10-19 18:11:03

@Cosine_Func

比较函数应当满足严格弱序

你这个“非严格逆序对排序部分”就啥也不是,把 < 的谓词形式替换成 <= 实在没什么完整地比较意义可言。

只能说 洛谷环境中 std::stable_sort 的实现 使用比较函数的要求没那么严格,目前我没看到谁因为写成后者有严重程序执行问题的,我不敢给你保证洛谷环境中它就绝对没问题。

你把 freopen 注释掉,N 改成 5e5+5return v<=b.v; 改成 return v<b.v;。也能过的。记录。

在洛谷评测用 std::sort,请务必把比较写成严格弱序,不允许 a<b&&b<a 成立,否则很有可能原地爆炸。


by Cosine_Func @ 2024-10-19 18:24:44

@Terrible 或许你说的有道理,但在我所说的站外题目中,< 不能 AC,但 <= 可以。这是那道站外题目:


by Terrible @ 2024-10-19 19:17:44

@Cosine_Func

就因为这点写法上的简化就让你想要深入它的原理吗?问题是这种东西也没有个保障啊?换个编译器结果完全可能会变的。

你没有给我题目链接,我只能按洛谷的环境里给你说。


by Terrible @ 2024-10-19 19:22:19

我看看这个题目,< 不对就是思路有问题了,想着用 <= 能够简化写法确实很冒险。


by Terrible @ 2024-10-19 19:38:31

std::stable_sort 底层的实现 可能 是类似这样一种归并排序:

合并两边序列,两边序列首位元素左边是 a,右边是 b,比较的时候调用比较函数 b\operatorname{cmp} a,如果返回真,那么让 b 先入新序列。如果对任意元素 x 都有 x\operatorname{cmp} x 为真,那么右边的元素总是先入新序列,最后总的归并结果就总是右边的相同元素归到左边,从而让相同元素之间倒序排列。

并非说任何编译器的内部实现都是这样,只是说有的编译器可能是这么实现的,C++ 并未在语言层面严格规定它的具体实现方式。C++ 语言层面的规范上是应该是不包含这种写法的,甚至具体到某个编译器也不一定有相关保证。


by mima @ 2024-12-08 17:57:18

全WA了


|