@morehigh
2017-05-20T21:31:52.000000Z
字数 4145
阅读 1102
线段数
A - Hotel POJ - 3667
旅馆里面有N(1 ≤ N ≤ 50,000)个房间,有M(1 ≤ M < 50,000)个操作,包含两类
1操作 需要占用连续的D个房间
2操作 从第X个房间到第X+D-1个房间被清空
进行1操作的时候,需要占用D个房间,需要查询输出r,表示从r到r+D的房间是空出来的
线段数连续区间合并问题,lsum表示从左边端点开始连续的空房间的个数,rsum表示从最右边端点开始向左连续的空房间的个数,msum表示此区间最大连续区间,如果最大的连续区间小于要占用的区间D,则表示不满足条件输出‘0’。col表示lazy数组,如果col为-1表示不存在向下传递数据。pushdown表示向下传递标记,pushup表示向上传递最大父亲区间的最大连续区间。
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn=50005;
int lsum[maxn*4], rsum[maxn*4], msum[maxn*4];
int col[maxn*4];
void push_down(int rt,int m)
{
if(col[rt]!=-1)
{
col[rt<<1]=col[rt<<1|1]=col[rt];
msum[rt<<1]=lsum[rt<<1]=rsum[rt<<1]=col[rt]?0:m-(m>>1);
msum[rt<<1|1]=lsum[rt<<1|1]=rsum[rt<<1|1]=col[rt]?0:(m>>1);
col[rt]=-1;
}
}
void push_up(int rt, int m) {
lsum[rt]=lsum[rt<<1];
rsum[rt]=rsum[rt<<1|1];
if(lsum[rt]==m-(m>>1)) lsum[rt]+=lsum[rt<<1|1];
if(rsum[rt] == (m>>1)) rsum[rt]+=rsum[rt<<1];
msum[rt]=max(lsum[rt<<1|1]+rsum[rt<<1], max(msum[rt<<1], msum[rt<<1|1]));
}
void build(int l,int r,int rt)
{
msum[rt]=lsum[rt]=rsum[rt]=r-l+1;
col[rt]=-1;
if(l==r) return ;
int mid=(l+r)>>1;
build(l,mid,rt<<1);
build(mid+1,r,rt<<1|1);
}
void update(int L,int R,int c,int rt,int l,int r)
{
if(L<=l&&R>=r){
msum[rt]=lsum[rt]=rsum[rt]=c?0:r-l+1;
col[rt]=c;
return ;
}
push_down(rt,r-l+1);
int mid=(l+r)>>1;
if(L<=mid) update(L,R,c,rt<<1,l,mid);
if(R>mid) update(L,R,c,rt<<1|1,mid+1,r);
push_up(rt,r-l+1);
}
int query(int wid, int rt, int l, int r) {
if(l == r) return l;
push_down(rt, r - l + 1);
int mid = (l + r) >> 1;
if(msum[rt << 1] >= wid) return query(wid, rt<<1,l,mid);
else if(rsum[rt << 1] + lsum[rt << 1|1] >= wid) return mid - rsum[rt << 1] + 1;
return query(wid,rt<<1|1,mid+1,r);
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
build(1,n,1);
while(m--)
{
int x,a,b;
scanf("%d",&x);
if(x==1)
{
scanf("%d",&a);
if(msum[1]<a) printf("0\n");
else{
int l=query(a,1,1,n);
printf("%d\n",l);
update(l,l+a-1,1,1,1,n);
}
}else{
scanf("%d%d",&a,&b);
update(a,a+b-1,0,1,1,n);
}
}
return 0;
}
B - A Corrupt Mayor's Performance Art HDU - 5023
输入两个数据 N 和 M (0 < N <= 1,000,000; 0<M<=100,000),表示在长度为N的墙壁上进行M个操作,涂颜色,一共有30种颜色,
1) P a b c 在a到b区间涂上颜色c
2) Q a b 查询a,b区间一共有几种颜色( 0 < a<=b <= N).
用到二进制存储压缩记录每个线段数区间所包含的颜色,初始颜色为2,pushdown表示将更新得到的颜色向下传递,更新时将需要更新的颜色存储到add数组中,减少时间复杂度,pushup将子区间更改的颜色传递给父亲节点,其中用到了位运算。
#include <bits/stdc++.h>
using namespace std;
const int N=1100056;
char s[10];
long long sum[N*4],add[N*4];
void pushdown(int rt)
{
if(add[rt])
{
add[rt<<1]=add[rt<<1|1]=add[rt];
sum[rt<<1]=add[rt];
sum[rt<<1|1]=add[rt];
add[rt]=0;
}
}
void pushup(int rt)
{
sum[rt]=sum[rt<<1]|sum[rt<<1|1];
}
void build(int rt,int l,int r)
{
add[rt]=0;
if(l==r)
{
sum[rt]=2;
return ;
}
int mid=(l+r)>>1;
build(rt<<1,l,mid);
build(rt<<1|1,mid+1,r);
pushup(rt);
}
void update(int L,int R,int c,int rt,int l,int r)
{
if(L<=l&&R>=r)
{
add[rt]=1<<(c-1);
sum[rt]=1<<(c-1);
return ;
}
pushdown(rt);
int mid=(l+r)>>1;
if(L<=mid)
update(L,R,c,rt<<1,l,mid);
if(R>mid)
update(L,R,c,rt<<1|1,mid+1,r);
pushup(rt);
}
long long query(int a,int b,int rt,int l,int r)
{
if(a<=l&&b>=r)
{
return sum[rt];
}
pushdown(rt);
long long ret=0;
int mid=(l+r)>>1;
if(a<=mid) ret|=query(a,b,rt<<1,l,mid);
if(b>mid) ret|=query(a,b,rt<<1|1,mid+1,r);
return ret;
}
int main()
{
int n,m;
int a,b,c;
while(~scanf("%d%d",&n,&m))
{
if(n==0&&m==0)
break;
build(1,1,n);
while(m--)
{
scanf("%s",s);
if(s[0]=='P')
{
scanf("%d%d%d",&a,&b,&c);
update(a,b,c,1,1,n);
}else{
scanf("%d%d",&a,&b);
long long t=query(a,b,1,1,n);
int flag=0;
for(int i=1;i<=30;i++)
{
if(t>>(i-1)&1 && flag==0)
{
printf("%d",i);
flag = 1;
}
else if(t>>(i-1)&1)
printf(" %d",i);
}
printf("\n");
}
}
}
return 0;
}
C - Assignment HDU - 5289
一个公司有n个员工,每个员工有一个大小为x能力,老板想把能力差大小不超过k的员工分到一组,求出老板能把员工分成多少组。(1<=n<=100000, 0<k<=10^9)
用ST做一个预处理,处理得到的数组mx[i][j]表示区间i到i^j中最大的数字。mn[i][j]表示区间i到i^j中最小的数字。然后要用到二分查找,判断i到j区间最大值与最小值差小于k。计算满足条件的区间数。
#include <bits/stdc++.h>
#define N 100005
using namespace std;
int a[N];
int mx[N][21], mn[N][21];
int n, k;
void ST()
{
for(int j=1;(1<<j)<=n;j++)
{
for(int i=1;i+(1<<j)-1<=n;i++)
{
int p = 1<<(j - 1);
mx[i][j]=max(mx[i][j-1],mx[i+p][j-1]);
mn[i][j]=min(mn[i][j-1],mn[i+p][j-1]);
}
}
}
int sol(int x,int y)
{
int p=log2(y-x+1.0);
int mxx=max(mx[x][p],mx[y-(1<<p)+1][p]);
int mnn=min(mn[x][p],mn[y-(1<<p)+1][p]);
return mxx-mnn;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
mx[i][0]=mn[i][0]=a[i];
}
ST();
long long ans=0;
for(int i=1;i<=n;i++)
{
int l=i,r=n;
while(l<=r)
{
int mid=(l+r)>>1;
if(sol(i,mid)<k) l=mid+1;
else
r=mid-1;
}
ans += (r * 1LL - i + 1);
}
cout<<ans<<endl;
}
return 0;
}