bzoj4631 踩气球 (树状数组+线段树)
4631: 踩气球
令\(L[i]\)为一段全\(0\)区间的左端点,\(R[i]\)为右端点;
把一个点\(i\)变成\(0\),相当于把它左右两段全\(0\)的区间连起来;
此时所有 \(L[i-1]<=l<=i\) 且 \(i<=r<=R[i+1]\) 的区间都会变得愉悦;
然后就变成了二维数点,树状数组+线段树,边界特判一下就行了;
AC GET☆DAZE
#include<algorithm>
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define N 100039
#define mod 20070831
#define inf 0x3f3f3f3f
#define ll long long
using namespace std;
struct Seg_Tree
{
int ls,rs,w;
}tree[N*2*39];
int n,m,q,num[N],L[N],R[N],tot,root[N],ans;
int make_new(int &k)
{
return !k ? k=++tot : k;
}
void update(int k,int l,int r,int v)
{
tree[k].w++;
if(l==r) return;
int mid=l+r>>1;
if(v<=mid) update(make_new(tree[k].ls),l,mid,v);
else update(make_new(tree[k].rs),mid+1,r,v);
}
int query(int k,int l,int r,int lv,int rv)
{
if(!k || (lv<=l && r<=rv)) return tree[k].w;
int mid=l+r>>1;
if(rv<=mid) return query(tree[k].ls,l,mid,lv,rv);
else if(mid<lv) return query(tree[k].rs,mid+1,r,lv,rv);
else return query(tree[k].ls,l,mid,lv,mid)+query(tree[k].rs,mid+1,r,mid+1,rv);
}
void update_bit(int p,int v)
{
while(p<=n)
{
update(make_new(root[p]),1,n,v);
p+=(-p&p);
}
}
int query_bit(int p,int l,int r)
{
int res=0;
while(p)
{
res+=query(root[p],1,n,l,r);
p-=(-p&p);
}
return res;
}
int main()
{
scanf("%d%d",&n,&m);
for(int a=1;a<=n;a++)
{
scanf("%d",&num[a]);
L[a]=R[a]=a;
}
for(int a=1,b,c;a<=m;a++)
{
scanf("%d%d",&b,&c);
update_bit(b,c);
}
scanf("%d",&q);
for(int a=1,b,c,d;a<=q;a++)
{
scanf("%d",&b);
((b+=ans-1)%=n)++;
num[b]--;
if(!num[b])
{
c=((b>1 && !num[b-1]) ? L[b-1] : b);
d=((b<n && !num[b+1]) ? R[b+1] : b);
ans+=query_bit(b,b,d)-query_bit(c-1,b,d);
if(b>1 && !num[b-1] && b<n && !num[b+1])
{
L[R[b+1]]=L[b-1],R[L[b-1]]=R[b+1];
}
else if(b>1 && !num[b-1]) L[b]=L[b-1],R[L[b-1]]=b;
else if(b<n && !num[b+1]) L[R[b+1]]=b,R[b]=R[b+1];
}
printf("%d\n",ans);
}
return 0;
}
散りぬべき 時知りてこそ 世の中の 花も花なれ 人も人なれ