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;
}
posted @ 2026-06-16 12:10  kzssCCC  阅读(13)  评论(0)    收藏  举报