基础用法
逆序对 atcoder.jp/contests/ab…
#include <bits/stdc++.h>
using namespace std;
using ll=unsigned long long;
template<typename T>
struct ft{
int n;
std::vector<T>data;
ft(int n_):n(n_),data(n_+1,0){}
void add(int idx,T de){
for(++idx;idx<=n;idx+=idx&-idx){
data[idx]+=de;
}
}
T sum(int idx){
T res=0;
for(;idx>0;idx-=idx&-idx){res+=data[idx];}return res;
}T sum(int l,int r){return sum(r)-sum(l);}
};
void so(){
}int main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int n;ll k;
cin>>n>>k;
vector<int>p(n);
for(int i=0;i<n;i++){
cin>>p[i];p[i]--;
}auto solve=[&](ll k)->ll{
ft<ll>bit(n);
ll now=0;ll ans=0;
int r=0;
for(int l=0;l<n;l++){
if(r<l)r=l;
while(r<n&&now+bit.sum(p[r],n)<=k){
//当前以存在的数中,比p[r]大的数的数量
now+=bit.sum(p[r],n);
bit.add(p[r],1);
r++;
}ans+=r-l;
now-=bit.sum(0,p[l]);//减少的逆序对数是比p[r]小的数的数量
bit.add(p[l],-1);//树状数组中剔除
}return ans;
};ll ans=solve(k)-(k>0?solve(k-1):0);
cout<<ans<<'\n';
}
E - LEQ
#include <bits/stdc++.h>
using namespace std;
using ll=long long;
const ll mod=998244353;
struct bt{
int N;
vector<ll>bit;
bt(int n):N(n){bit.resize(N+1,0);
}ll ad(ll x,ll y){
return (x+y)%mod;
}void add(int x,ll a){
x++;
for(x;x<=N;x+=(x&-x))bit[x]=ad(bit[x],a);
}ll sum(int x){
x++;
ll ret=0;
for(x;x>0;x-=(x&-x))ret=ad(ret,bit[x]);
return ret;
}
};
ll modpow(ll x, ll y){
ll ret = 1;
while(0 < y){
if(y & 1){
ret *= x;
ret %= mod;
}
x *= x;
x %= mod;
y >>= 1;
}
return ret;
}
int comp(vector<int>&a){
map<int,int>me;
for(auto p:a)me[p]=0;
int sz=0;
for(auto &p:me)p.second=sz++;
for(auto &p:a)p=me[p];
return sz;
}
int main(){
const ll div=modpow(2,mod-2);
int N;cin>>N;
vector<int>a(N);
for(int i=0;i<N;i++)cin>>a[i];
int n=comp(a);
bt bit(n);
ll ans=0;
for(int i=0;i<N;i++){
ans+=bit.sum(a[i])*modpow(2,i);
ans%=mod;
bit.add(a[i],modpow(div,i+1));
}
cout<<ans;
}
思路
-------------------- 核心公式 1 --------------------
bit.sum(a[j]) = 所有 i<j 且 A[i] ≤ A[j] 的 (1/2^(i+1)) 之和
乘上 2^j 就等于题解中的 B_j × 2^(j-1)
对应题解:ans += B_j × 2^(j-1)
ans = (ans + bit.sum(a[j]) * modpow(2, j)) % mod;
-------------------- 核心公式 2 --------------------
把当前位置 j 加入树状数组
存入的值:1 / 2^(j+1)
对应题解:维护 1/2^i
bit.add(a[j], modpow(div, j + 1));
因为题目需要: 对每个 j,求左边 i<j 且 A[i]≤A[j] 的权值和, 还要动态插入数值。
这种**“前缀查询 + 单点更新 + 按值大小统计”**的操作, 树状数组是最优选择,复杂度 (O(N\log N)) 能过 3e5。