@meredith233
2017-06-01T21:20:20.000000Z
字数 4390
阅读 787
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 50005
using 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;
else
return 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 1000005
using 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 100005
using namespace std;
int ar[MAX];
int n,m;
int dp1[MAX][30];//max
int dp2[MAX][30];//min
void 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;
}