【算法】【树状数组】

1 阅读1分钟

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;
}

思路

图片.png -------------------- 核心公式 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。