2019~2020icpc亚洲区域赛徐州站H. Yuuki and a problem
2019~2020icpc亚洲区域赛徐州站H. Yuuki and a problem
题意:
给定一个长度为\(n\)的序列,有两种操作:
- 1:单点修改。
- 2:查询区间\([L,R]\)范围内所有子集和中没出现的最小正整数。
思路:
对于维护序列的问题大概率是数据结构的题目了,先确定一下题目的性质。
操作2需要我们提取\([l,r]\)范围内的值,这可以用主席树解决,同时需要带修,所以可以用树状数组套主席树完成。
确定是树套树后,考虑怎么维护操作2。
我们考虑一个节点,先看看能不能表示成1,如果这个节点代表的区间一个1都没有,那他的答案为1。
假设答案已经可以构成\([1,x]\)了。
考虑当前节点代表的区间内值为\([1,x+1]\)的数字的和为sum。
那么我们就可以构成\([1,sum]\)这个区间了,如果\(sum==x\),那么答案就是\(x+1\)。
这个过程可以暴力跑,因为他是一个斐波那契数列,不到多少项就到2e5了。
所以我们操作2就相当于是模拟这样一个过程。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5+10;
int n, m, len;
ll a[maxn];
inline int lowbit(int x){
return x&(-x);
}
ll sum[maxn*80];
int ls[maxn*80];
int rs[maxn*80];
int rt[maxn*80];
int tot;
void update_SgT(int &rt, int l, int r, int x, int val)
{
if(!rt) rt = ++tot;
if(l == r)
{
sum[rt] += val;
return;
}
int mid = (l+r)>>1;
if(x <= mid) update_SgT(ls[rt], l, mid, x, val);
else update_SgT(rs[rt], mid+1, r, x, val);
sum[rt] = sum[ls[rt]] + sum[rs[rt]];
}
void update_BIT(int pos, int x, int val)
{
for(int i = pos; i <= n; i += lowbit(i))
update_SgT(rt[i], 1, len, x, val);
}
int rt1[maxn], rt2[maxn], cnt1, cnt2;
void locate(int l, int r)
{
cnt1 = cnt2 = 0;
for(int i = l-1; i; i -= lowbit(i))
rt1[++cnt1] = rt[i];
for(int i = r; i; i -= lowbit(i))
rt2[++cnt2] = rt[i];
}
ll ask(int l, int r, int k)
{
ll ans = 0;
if(r == k)
{
for(int i = 1; i <= cnt1; i++)
ans -= sum[rt1[i]];
for(int i = 1; i<= cnt2; i++)
ans += sum[rt2[i]];
return ans;
}
int mid = (l+r)>>1;
if(k <= mid)
{
for(int i = 1; i <= cnt1; i++)
rt1[i] = ls[rt1[i]];
for(int i = 1; i <= cnt2; i++)
rt2[i] = ls[rt2[i]];
return ask(l, mid, k);
}
else
{
for(int i = 1; i <= cnt1; i++)
ans -= sum[ls[rt1[i]]];
for(int i = 1; i <= cnt2; i++)
ans += sum[ls[rt2[i]]];
for(int i = 1; i <= cnt1; i++)
rt1[i] = rs[rt1[i]];
for(int i = 1; i <= cnt2; i++)
rt2[i] = rs[rt2[i]];
return ans + ask(mid+1, r, k);
}
}
int main()
{
scanf("%d%d", &n, &m);
len = maxn-10;
for(int i = 1; i <= n; i++)
scanf("%lld", &a[i]);
for(int i = 1; i <= n; i++)
update_BIT(i, a[i], a[i]);
for(int i = 1, op, x, y; i <= m; i++)
{
scanf("%d%d%d", &op, &x, &y);
if(op == 1) //修改操作
{
update_BIT(x, a[x], -a[x]);
a[x] = y;
update_BIT(x, y, y);
}
else
{
ll now = 1;
ll s = 0;
while(true)
{
locate(x, y);
int t = min(now, 200000ll);
ll tmp = ask(1, len, t);
if(tmp == s)
{
printf("%lld\n", now);
break;
}
s = tmp, now = s+1;
}
}
}
return 0;
}