给出两种操作:
第i个0:在x位置插入一个长度为i的线段,并输出该线段共覆盖了多少之前增加的线段
1:删除第i次插入的线段
官方题解:对于新插入的线段,查询有多少个线段左端点大于等于该线段的左端点。 再查询有多少个线段的右端点大于该线段右端点, 两者之差就是答案。用两个树状数组搞定。时间复杂度nlog
思路非常好理解,直接用一个线段树记录区间的左端点和右端点就可以
#include "stdio.h" #include "string.h" #include "algorithm" using namespace std; const int inf=0x7fffffff; struct A { int op,l,r,x; } a[400010]; struct Y { int x,id; } y[400010]; struct Data { int l,r,a,b; } data[1600010]; bool cmp(Y a,Y b) { return a.x<b.x; } void build(int l,int r,int k) { data[k].l=l; data[k].r=r; data[k].a=data[k].b=0; if (l==r) return ; int mid=(l+r)/2; build(l,mid,k*2); build(mid+1,r,k*2+1); } int query(int l,int r,int k,int op) { if (l>r) return 0; if (data[k].l==l && data[k].r==r) { if (op==1) return data[k].a; else return data[k].b; } int mid=(data[k].l+data[k].r)/2; if (r<=mid) return query(l,r,k*2,op); else if (l>mid) return query(l,r,k*2+1,op); else return query(l,mid,k*2,op)+query(mid+1,r,k*2+1,op); } void updata(int n,int k,int op,int x) { if (op==1) data[k].a+=x; else data[k].b+=x; if (data[k].l==n && data[k].r==n) return ; if (n<=data[k*2].r) updata(n,k*2,op,x); else updata(n,k*2+1,op,x); } int main() { int Case,n,i,x,cnt; Case=1; while (scanf("%d",&n)!=EOF) { cnt=1; for (i=0; i<n; i++) { scanf("%d",&a[i].op); if (a[i].op==0) { scanf("%d",&a[i].l); a[i].r=a[i].l+cnt; cnt++; } else { scanf("%d",&x); x--; a[i].x=x; } y[i*2].x=a[i].l; y[i*2].id=-i-1; y[i*2+1].x=a[i].r; y[i*2+1].id=i+1; } sort(y,y+n*2,cmp); cnt=0; if (y[0].id<0) a[-y[0].id-1].l=0; else a[y[0].id-1].r=0; for (i=1; i<n*2; i++) { if (y[i].x!=y[i-1].x) cnt++; if (y[i].id<0) a[-y[i].id-1].l=cnt; else a[y[i].id-1].r=cnt; } build(0,cnt,1); printf("Case #%d: ",Case++); int temp=0; for (i=0; i<n; i++) { if (a[i].op==0) { printf("%d ",query(a[i].l,cnt,1,1)-query(a[i].r+1,cnt,1,2)); updata(a[i].l,1,1,1); updata(a[i].r,1,2,1); a[temp].l=a[i].l; a[temp].r=a[i].r; temp++; } else { updata(a[a[i].x].l,1,1,-1); updata(a[a[i].x].r,1,2,-1); } } } return 0; }