@morehigh
2017-05-20T13:31:52.000000Z
字数 4145
阅读 1242
线段数
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区间涂上颜色c2) 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 100005using 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;elser=mid-1;}ans += (r * 1LL - i + 1);}cout<<ans<<endl;}return 0;}