hdu4614 二分法+段树
意甲冠军:给你1-n花瓶 。起初,所有的空,今天,有两种操作模式,
1:从花瓶a開始插入b朵花 假设不能插进去 输出字符串 否则输出最多插入的起点和终点;
2:把a-b的花瓶清空 输出处理花的个数;
结构体数组num【i】表示节点i空瓶的数目
线段树 開始deal函数对整个树初始化,update()更新函数 find()查询区间有多少个空瓶; 对于操作1 关键点是找到起点和终点 这里用二分 在【a,n】进行二分,
先二分起点 注意左右区间的变换(wa了好多次==) 然后在起点和n之间二分终点 最后更新 输出 对于操作2 直接查询就可以;
#include<stdio.h> #include<string.h> #include<iostream> using namespace std; #define LL(x) (x<<1) #define RR(x) ((x<<1)|1) struct node { int cont; }num[50000*4]; int deal(int L,int R,int point) { num[point].cont=R-L+1; if(L==R) return 0; int mid=(L+R)/2; deal(L,mid,LL(point)); deal(mid+1,R,RR(point)); return 0; } int update(int L,int R,int left,int right,int point,int k) { if(L==left&&R==right) { if(k==1) num[point].cont=R-L+1; else num[point].cont=0; return 0; } int mid=(L+R)/2; if(num[point].cont==R-L+1) { num[LL(point)].cont=mid-L+1; num[RR(point)].cont=R-mid; } if(num[point].cont==0) { num[LL(point)].cont=0; num[RR(point)].cont=0; } if(right<=mid) { update(L,mid,left,right,LL(point),k); } else if(left>mid) { update(mid+1,R,left,right,RR(point),k); } else { update(L,mid,left,mid,LL(point),k); update(mid+1,R,mid+1,right,RR(point),k); } num[point].cont=num[LL(point)].cont+num[RR(point)].cont; return 0; } int find(int L,int R,int left,int right,int point) { if(L==left&&R==right) return num[point].cont; int sum=0; int mid=(L+R)/2; if(num[point].cont==R-L+1) return right-left+1; if(num[point].cont==0) return 0; if(right<=mid) sum+=find(L,mid,left,right,LL(point)); else if(left>mid) sum+=find(mid+1,R,left,right,RR(point)); else { sum+=find(L,mid,left,mid,LL(point)); sum+=find(mid+1,R,mid+1,right,RR(point)); } return sum; } int main() { int n,m,k,i,j,T,a,b; scanf("%d",&T); while(T--) { scanf("%d%d",&n,&m); deal(1,n,1); for(i=1;i<=m;i++) { scanf("%d%d%d",&k,&a,&b); if(k==1) { a+=1; int cont=find(1,n,a,n,1); if(cont==0) printf("Can not put any one.\n"); else { int left,right,mid; int star,end; left=a; right=n; while(left<=right) { mid=(left+right)/2; if(find(1,n,left,mid,1)>0) { right=mid-1; star=mid; } else left=mid+1; } if(cont<=b) { left=a; right=n; while(left<=right) { mid=(left+right)/2; if(find(1,n,mid,right,1)>0) { left=mid+1; end=mid; } else right=mid-1; } //end=right; } else { left=a; right=n; while(left<=right) { mid=(left+right)/2; if(find(1,n,star,mid,1)>=b) { right=mid-1; end=mid; } else left=mid+1; } //end=left; } printf("%d %d\n",star-1,end-1); update(1,n,star,end,1,-1); } } else { printf("%d\n",b-a+1-find(1,n,a+1,b+1,1)); update(1,n,a+1,b+1,1,1); } } printf("\n"); } return 0; }