CF2179H 思路分享(二阶 k 步差分)
https://codeforces.com/problemset/problem/2179/H
题意概述
长度为 \(n\) 的序列 \(a\) 初始值全 \(0\),定义 \(f(x)=x\cdot lowbit(x)\).
\(q\) 个操作,每个操作对 \([l,r]\) 范围内所有 \(a_i\) 加上 \(f(i-l+1)\),求最终每个位置的 \(a_i\).
\(1\le n,q \le 2\cdot 10^5\).
思路
假设 \(lowbit=2^k\),有如下规律:
-
第一个出现位置为 \(2^k\).
-
出现位置为等差数列,公差为 \(2^{k+1}\).
因为不同 \(lowbit\) 数量为 \(log\) 级别,考虑分组 \(k\) 步差分维护.
对于 \(lowbit=2^k\),位置 \(i\) 的增量为 \((i-l+1)\cdot 2^k\),二价差分维护即可.
时间复杂度 \(\mathcal{O}((n+q)\log n)\).
代码
//author:kzssCCC
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void solve(){
int n,q;
cin >> n >> q;
vector<vector<ll>> diff1(n+1,vector<ll>(20));
vector<vector<ll>> diff2(n+1,vector<ll>(20));
while (q--){
int l,r;
cin >> l >> r;
for (int k=0;k<20;k++){
int s = l-1+(1<<k);
if (s>r) break;
int t = s+(r-s)/(1<<k+1)*(1<<k+1);
diff1[s][k] += 1;
if (t+(1<<k+1)<=n) diff1[t+(1<<k+1)][k] -= 1;
diff2[s][k] += 1-l;
if (t+(1<<k+1)<=n) diff2[t+(1<<k+1)][k] -= 1-l;
}
}
for (int k=0;k<20;k++){
for (int i=1<<k+1;i<=n;i++){
diff1[i][k] += diff1[i-(1<<k+1)][k];
diff2[i][k] += diff2[i-(1<<k+1)][k];
}
}
for (int i=1;i<=n;i++){
ll d1=0,d2=0;
for (int k=0;k<20;k++){
d1 += (ll)diff1[i][k]*(1<<k);
d2 += (ll)diff2[i][k]*(1<<k);
}
cout << d1*i+d2 << ' ';
}
cout << '\n';
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
int t = 1;
cin >> t;
while (t--) solve();
return 0;
}

浙公网安备 33010602011771号