@meredith233
2017-06-01T13:20:20.000000Z
字数 4390
阅读 924
homework
有一家旅馆,有标号1~n个房间。现给定两种操作。1为给定一个人数,求能放下这个人数的开始位置(必须连续放置),且这个位置尽量小。2为将区间i到j清空(check out)。
线段树区间合并。通过sum记录区间内空房间数,lsum记录从某点向右有多少个空房间,rsum记录从某点向左有多少个空房间,vis记录某区间房间是否被占用(0表没有,1表有,-1表示没有操作)。
#include <cstdio>#include <algorithm>#include <iostream>#include <cstring>#include <queue>#define INF 0x3f3f3f#define MAX 50005using namespace std;int lsum[MAX*4],rsum[MAX*4],sum[MAX*4],vis[MAX*4];int n,m;void build(int num,int l,int r){vis[num]=-1;lsum[num]=rsum[num]=sum[num]=r-l+1;if(l==r)return;int mid=(l+r)>>1;build(num<<1,l,mid);build(num<<1|1,mid+1,r);}void pushdown(int num,int k){if(vis[num]!=-1){vis[num<<1]=vis[num<<1|1]=vis[num];lsum[num<<1]=rsum[num<<1]=sum[num<<1]=vis[num]?0:(k-(k>>1));lsum[num<<1|1]=rsum[num<<1|1]=sum[num<<1|1]=vis[num]?0:k>>1;vis[num]=-1;}}void pushup(int num,int k){lsum[num]=lsum[num<<1];rsum[num]=rsum[num<<1|1];if(lsum[num]==(k-(k>>1)))lsum[num]+=lsum[num<<1|1];if(rsum[num]==k>>1)rsum[num]+=rsum[num<<1];sum[num]=max(rsum[num<<1]+lsum[num<<1|1],max(sum[num<<1],sum[num<<1|1]));}void update(int num,int l,int r,int x,int y,int z){if(x<=l&&y>=r){lsum[num]=rsum[num]=sum[num]=z?0:(r-l+1);vis[num]=z;return;}pushdown(num,r-l+1);int mid=(l+r)>>1;if(x<=mid)update(num<<1,l,mid,x,y,z);if(y>mid)update(num<<1|1,mid+1,r,x,y,z);pushup(num,r-l+1);}int query(int num,int l,int r,int x){if(l==r)return l;pushdown(num,r-l+1);int mid=(l+r)>>1;if(sum[num<<1]>=x)return query(num<<1,l,mid,x);else if(rsum[num<<1]+lsum[num<<1|1]>=x)return mid-rsum[num<<1]+1;elsereturn query(num<<1|1,mid+1,r,x);}int main(){while(~scanf("%d%d",&n,&m)){build(1,1,n);while(m--){int a,b,c;scanf("%d",&a);if(a==1){scanf("%d",&b);if(sum[1]<b)printf("0\n");else{int pos=query(1,1,n,b);printf("%d\n",pos);update(1,1,n,pos,pos+b-1,1);}}else if(a==2){scanf("%d%d",&b,&c);update(1,1,n,b,b+c-1,0);}}}return 0;}
有一堵墙,有30种颜色标号1-30,墙的默认颜色为2号,现给定两种操作,一为给i到j区间涂上一种颜色,二位查询i到j区间共涂有多少种颜色。
线段树,通过位操作给定(1)<<(i)为颜色值保存,向上更新时进行按位或运算。更新时直接全部更新为涂上的颜色值即可。(初始化爆炸WA两发)
#include <cstdio>#include <algorithm>#include <iostream>#include <cstring>#include <queue>#define INF 0x3f3f3f#define MAX 1000005using namespace std;int tre[MAX*4];bool laz[MAX*4];int n,m;void build(int num,int l,int r){if(l==r){tre[num]=4;return;}int mid=(l+r)>>1;build(num<<1,l,mid);build(num<<1|1,mid+1,r);tre[num]=tre[num<<1]|tre[num<<1|1];}void pushdown(int num){if(laz[num]){tre[num<<1]=tre[num];tre[num<<1|1]=tre[num];laz[num<<1]=true;laz[num<<1|1]=true;laz[num]=false;}}void update(int num,int l,int r,int x,int y,int z){if(x<=l&&y>=r){tre[num]=(1<<z);laz[num]=true;return;}pushdown(num);int mid=(l+r)>>1;if(x<=mid)update(num*2,l,mid,x,y,z);if(y>mid)update(num*2+1,mid+1,r,x,y,z);tre[num]=tre[num*2]|tre[num*2+1];}int query(int num,int l,int r,int x,int y){if(x<=l&&y>=r){return tre[num];}pushdown(num);int mid=(l+r)>>1;int ans=0;if(x<=mid)ans|=query(num*2,l,mid,x,y);if(y>mid)ans|=query(num*2+1,mid+1,r,x,y);return ans;}int main(){while(~scanf("%d%d",&n,&m)){memset(laz,false,sizeof(laz));if(n==m&&n==0)break;build(1,1,n);while(m--){char c;scanf(" %c",&c);if(c=='P'){int a,b,c;scanf("%d%d%d",&a,&b,&c);update(1,1,n,a,b,c);}else if(c=='Q'){int a,b;scanf("%d%d",&a,&b);int ans=query(1,1,n,a,b);int flag=0;for(int i=1; i<=30; i++){if(ans>>(i)&1 && flag==0){printf("%d",i);flag = 1;}else if(ans>>(i)&1)printf(" %d",i);}printf("\n");}}}return 0;}
n名员工,每人有一个能力值ai。给定一个差值k,为一个连续区间内最大值与最小值之差的最大值,求有多少个区间满足这个情况。
st保存区间最大值与区间最小值。查询部分运用二分。枚举右端点i,如果当前区间满足,则这之间所有端点都可作为左端点,不满足时左端点l移动。
#include <cstdio>#include <algorithm>#include <iostream>#include <cstring>#include <queue>#include <cmath>#define INF 0x3f3f3f#define MAX 100005using namespace std;int ar[MAX];int n,m;int dp1[MAX][30];//maxint dp2[MAX][30];//minvoid init(){for(int i=0;i<=n;i++){dp1[i][0]=ar[i];dp2[i][0]=ar[i];}for(int j=1;(1<<j)<=n;j++){for(int i=1;i+(1<<j)-1<=n;i++){dp1[i][j]=max(dp1[i][j-1],dp1[i+(1<<(j-1))][j-1]);dp2[i][j]=min(dp2[i][j-1],dp2[i+(1<<(j-1))][j-1]);}}}int querymin(int l,int r){int k=(int)(log(double(r-l+1))/log((double)2));return min(dp2[l][k],dp2[r-(1<<k)+1][k]);}int querymax(int l,int r){int k=(int)(log(double(r-l+1))/log((double)2));return max(dp1[l][k],dp1[r-(1<<k)+1][k]);}int main(){int t;scanf("%d",&t);while(t--){scanf("%d%d",&n,&m);for(int i=1;i<=n;i++)scanf("%d",&ar[i]);init();long long sum=0;int k=1;for(int i=1;i<=n;i++){int l=k,r=i;while(l<=r){int mid=(l+r)>>1;int lo=querymin(mid,i);int ma=querymax(mid,i);int x=ma-lo;if(x>=m)l=mid+1;else if(x<m)r=mid-1;}k=l;sum+=i-l+1;}printf("%lld\n",sum);}return 0;}