线段树
我居然想了一个半小时才想出来
读完题可以发现如果布不同地雷的区间如果相交的话,地雷是不会覆盖的
两种不同的地雷会共存在一格中
那么在问题可以转化,所求答案就是当前询问的区间与之前布地雷的区间有多少个相交或包含
(我没想到)
那么考虑一个区间不与另一个区间相交的条件
即$r_{1}<l_{2}$或$l_{1}>r_{2}$
那么可以用线段树维护对于每个点区间右端点小于等于这点的区间数量$s1$,和左端点大于等于这点的区间数量$s2$
那么询问时答案就是当前布地雷的总数量减去$s1[l-1]$和$s2[r+1]$
#include <bits/stdc++.h> using namespace std; const int MAXN=2*1e5+100; int n,m,s[MAXN][3],tot; struct node { int l,r,lazy[3]; }sh[MAXN*4]; void pushdown(int x) { for (int i=1;i<=2;i++) { if (sh[x+x].l==sh[x+x].r) s[sh[x+x].l][i]+=sh[x].lazy[i]; if (sh[x+x+1].l==sh[x+x+1].r) s[sh[x+x+1].l][i]+=sh[x].lazy[i]; sh[x+x].lazy[i]+=sh[x].lazy[i]; sh[x+x+1].lazy[i]+=sh[x].lazy[i]; sh[x].lazy[i]=0; } } void build(int x,int ll,int rr) { sh[x].l=ll; sh[x].r=rr; if (ll==rr) return; int mid; mid=(ll+rr)>>1; build(x+x,ll,mid); build(x+x+1,mid+1,rr); } void change(int x,int ll,int rr,int kind)//区间修改 { if (sh[x].l>=ll && sh[x].r<=rr) { sh[x].lazy[kind]++; if (sh[x].l==sh[x].r)//注意如果当前修改的已经是单个元素,修改信息 s[sh[x].l][kind]++; return; } pushdown(x); int mid; mid=(sh[x].l+sh[x].r)>>1; if (ll<=mid) change(x+x,ll,rr,kind); if (rr>mid) change(x+x+1,ll,rr,kind); } void allchange(int x,int wh)//下放懒标记 { pushdown(x); if (sh[x].l==sh[x].r) return; int mid; mid=(sh[x].l+sh[x].r)>>1; if (wh<=mid) allchange(x+x,wh); else allchange(x+x+1,wh); } int main() { scanf("%d%d",&n,&m); build(1,1,n); for (int i=1;i<=m;i++) { int q,l,r; scanf("%d%d%d",&q,&l,&r); if (q==1) { change(1,r,n,1); change(1,1,l,2); tot++; } else { allchange(1,l-1); allchange(1,r+1); printf("%d ",tot-s[l-1][1]-s[r+1][2]);//答案 } } }