P8618 [蓝桥杯 2014 国 B] Log 大侠

链接

https://www.luogu.com.cn/problem/P8618

思路

注意到区间修改 + 区间查询。所以采用线段树。
这里对线段树的板子进行修改。注意到求log2+1那么最后的不动点一定落在1/2.所以当一个单点的值为1/2时设置tag[p]=true;然后push_up的时候用tag[p]=tag[ls(p)]&&tag[rs(p)]进行递推。复杂度:每个点最多修改30次,查询一次用logn。所以总复杂度30*M*logn

代码

#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define int long long
#define itn long long
#define tin long long
#define ll long long
const int N = 1e5 + 10;
bool tag[N << 2];
ll a[N];
ll tree[N<<2];

ll ls(ll p) { return p << 1; }
ll rs(ll p) { return p << 1 | 1; }
void push_up(ll p)
{
	tree[p] = tree[ls(p)] + tree[rs(p)];
	tag[p] = tag[ls(p)] && tag[rs(p)];
}
void build(int p, int pl, int pr)
{
	int mid = (pl + pr) / 2;
	if (pl == pr)
	{
		tree[p] = a[pl];
		tag[p] = (tree[p]==1)||(tree[p]==2);
		return;
		
	}
	build(ls(p), pl, mid);
	build(rs(p), mid + 1, pr);
	push_up(p);
}
void update(int l, int r, int p, int pl, int pr)
{
	if (l <= pl and r >= pr and tag[p])
	{
		return;
	}
	else if (pl == pr)
	{
		tree[p] = log2(tree[p]) + 1;
		tag[p]= (tree[p] == 1) || (tree[p] == 2);
		return;
	}
	int mid = (pl + pr) >> 1;
	if (l <= mid)update(l, r, ls(p), pl, mid);
	if (r > mid)update(l, r, rs(p), mid + 1, pr);
	push_up(p);
}
ll query(ll l, ll r, int p, int pl, int pr)
{
	if (pl >= l and pr <= r)return tree[p];
	int mid = (pl + pr) >> 1;
	int res = 0;
	if (l <= mid)res+=query(l, r, ls(p), pl, mid);
	if (r > mid)res += query(l, r, rs(p), mid + 1, pr);
	return res;
}
int n, m;
void solve()
{
	cin >> n >> m;
	for (int i = 1; i <= n; i++)cin >> a[i];
	build(1, 1, n);
	for (int i = 0; i < m; i++)
	{
		int l, r; cin >> l >> r;
		update(l, r, 1, 1, n);
		cout << query(1, n, 1, 1, n) << '\n';
	}
}

signed main()
{
	IOS;
	solve();
	return 0;
}

posted @ 2025-04-11 11:12  WHUStar  阅读(8)  评论(0)    收藏  举报