标签:线段树
1 3 6 1 6 1 6 3 4 1 5 1 2 2 4
Case 1:1 2 3 5
这一题属于成段更新,需要用到lazy思想,题意是每个人按时间顺序从a站坐到b站,然后每趟车不能超过k个人,输出能够坐车的人。这里要注意从a站坐到b站,区间更新的是[a,b-1].这里先用线段树维护4个变量,l,r,max,cnt.l,r表示区间的左右端点,max表示这一段区间的最大人数,cnt表示这段的增量,也是lazy标志。
关于cnt和max怎么进行更新,这是个难的地方,想了很久。每次如果询问区间比当前整段区间小,那么把这整段区间的增量加到左右子树的增量上,然后再把增量加到左右子树的最大值上,最后这段区间的增量变为0.
<pre name="code" class="cpp">#include<iostream> #include<stdio.h> #include<string.h> #include<math.h> #include<vector> #include<map> #include<queue> #include<stack> #include<string> #include<algorithm> using namespace std; #define maxn 1000005 int num,k,a[100005]; int max(int a,int b){ return a>b?a:b; } struct node{ int l,r,max,cnt; }b[4*maxn]; void build(int l,int r,int i) { int mid; b[i].l=l;b[i].r=r;b[i].max=b[i].cnt=0; if(l==r)return; mid=(l+r)/2; build(l,mid,i*2); build(mid+1,r,i*2+1); } int question(int l,int r,int i) { int mid; if(b[i].l==l && b[i].r==r){ return b[i].max; } if(b[i].cnt){ b[i*2].cnt+=b[i].cnt;b[i*2+1].cnt+=b[i].cnt; b[i*2].max+=b[i].cnt;b[i*2+1].max+=b[i].cnt; b[i].cnt=0; } mid=(b[i].l+b[i].r)/2; if(r<=mid)return question(l,r,i*2); else if(l>mid)return question(l,r,i*2+1); else return max(question(l,mid,i*2),question(mid+1,r,i*2+1)); } void update(int l,int r,int i) { int mid; if(b[i].l==l && b[i].r==r){ b[i].cnt++;b[i].max++;return; } if(b[i].cnt){ b[i*2].cnt+=b[i].cnt;b[i*2+1].cnt+=b[i].cnt; b[i*2].max+=b[i].cnt;b[i*2+1].max+=b[i].cnt; b[i].cnt=0; } mid=(b[i].l+b[i].r)/2; if(r<=mid)update(l,r,i*2); else if(l>mid)update(l,r,i*2+1); else { update(l,mid,i*2); update(mid+1,r,i*2+1); } b[i].max=max(b[i*2].max,b[i*2+1].max); } int main() { int m,i,j,T,num1=0,c,d,t; scanf("%d",&T); while(T--) { num1++;t=0; printf("Case %d:\n",num1); scanf("%d%d",&k,&m); build(1,1000005,1); memset(a,0,sizeof(a)); for(i=1;i<=m;i++){ scanf("%d%d",&c,&d); d--; if(question(c,d,1)<k){ a[++t]=i; update(c,d,1); } } for(i=1;i<=t;i++){ printf("%d ",a[i]); } printf("\n\n"); } return 0; }
标签:线段树
原文地址:http://blog.csdn.net/kirito_acmer/article/details/46231305