2021 ICPC亚洲区域赛 昆明 M.Stone Games(主席树)
题面

题意
n个数,分别是 \(s_1,s_2,s_3 \dots s_n\) ,以及Q个询问,对于每个询问,有两个整数 \(l\) 和 \(r\) ,问对于区间 \(s_l \dots s_r\) ,从该区间任意取数求和无法得到的最小的正整数。
思路
显然, 当该区间没有1时答案为1。 我们假设该区间已经取了某些数可以相加得到 \([1,x]\) ,对于该区间未取的数, 若存在 \(x+1\) ,则可将 \(x+1\) 合并进答案,使我们从该区间取数相加可得的范围变为 \([1,2x+1]\) , 反之,若该区间不存在 \(x+1\) , 则答案就是 \(x+1\) 。
每个询问开始时, 首先查找区间内有多少个1, 也就是该区间内数字1的和, 假设和为 \(x\) ,代表该区间内至少可以组合出 \([1,x]\) 的数,重复上述操作查找 \(x+1\) ,直至查找不到, 则该数就是答案。 很显然, 以上的操作可以用主席树完成。
code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll maxn=1000000+10;
struct node
{
ll lson,rson;
ll sum;
}tree[maxn<<5];
ll n,tot,rt[maxn];
void change(ll &p,ll l,ll r,ll val)
{
tree[++tot]=tree[p];
p=tot;
tree[p].sum+=val;
if(l==r) return;
ll mid=(l+r)>>1;
if(val<=mid) change(tree[p].lson,l,mid,val);
else change(tree[p].rson,mid+1,r,val);
}
ll query(ll pl,ll pr,ll l,ll r ,ll val)
{
if(l==r) return tree[pr].sum-tree[pl].sum;
ll mid=(l+r)>>1;
if(val<=mid) return query(tree[pl].lson,tree[pr].lson,l,mid,val);
else return query(tree[pl].rson,tree[pr].rson,mid+1,r,val)+tree[tree[pr].lson].sum-tree[tree[pl].lson].sum;
}
int main()
{
ll q;
cin>>n>>q;
for(ll i=1;i<=n;i++)
{
ll num; cin>>num;
change(rt[i]=rt[i-1],1,1000000000+10,num);
}
ll ans=0,fuck=0;
for(ll i=0;i<q;i++)
{
ll l,r; cin>>l>>r;
l=(l+ans)%n+1;
r=(r+ans)%n+1;
if(l>r) swap(l,r);
ans=0;
while(1)
{
fuck=query(rt[l-1],rt[r],1,1000000000+10,ans+1);
if(ans==fuck) break;
ans=fuck;
}
ans++;
cout<<ans<<"\n";
}
return 0;
}

浙公网安备 33010602011771号