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

浙公网安备 33010602011771号