@sensitive-cs
2017-05-13T06:46:05.000000Z
字数 3282
阅读 1416
题解
B - A Corrupt Mayor's Performance Art
题意:
有一堵墙,分为n块,开始的时候每块颜色都是2,之后会针对由a到b的色块进行染色,颜色共有30,然后其中会有查询a到b的块由哪些颜色的操作,并且按照升序输出。
思路:
一开始按照区间修改的套路去做,但是很明显的颜色修改不可能覆盖每一块,会有bug,后来看题解知道用状态压缩的方式去表示是否有这种颜色,位运算果然是美妙的。
注意每次build以及update的时候最后要加上pushup。
然后在update中以及query中pushdown永远在递归前面。
代码:
#include <stdio.h>#include <string.h>const int mx = 1000005;int cl[mx << 2];int add[mx << 2];bool v[35];void pushup(int rt){cl[rt] = cl[rt << 1 | 1] | cl[rt << 1];}void pushdown(int rt){if (add[rt]){//cl[rt] = add[rt];add[rt << 1] = add[rt];add[rt << 1|1] = add[rt];cl[rt << 1] = add[rt];cl[rt << 1|1] = add[rt];add[rt] = 0;}}void build(int rt,int l,int r,int k){if (l == r){cl[rt] = k;return;}int m = (l + r) >> 1;build(rt << 1,l,m,k);build(rt << 1|1,m+1,r,k);pushup(rt);}void update(int rt,int ll,int rr,int k,int l,int r){if (l >= ll && r <= rr){cl[rt] = 1 << (k - 1);add[rt] = 1 << (k - 1);return;}int m = (l + r) >> 1;pushdown(rt);if (ll <= m){update(rt << 1,ll,rr,k,l,m);}if (rr > m){update(rt << 1|1,ll,rr,k,m+1,r);}pushup(rt);}long long query(int rt,int ll,int rr,int l,int r){if (l >= ll && r <= rr){return cl[rt];}int m = (l + r) >> 1;pushdown(rt);long long ret = 0;if (ll <= m){ret |= query(rt << 1,ll,rr,l,m);}if (rr > m){ret |= query(rt << 1|1,ll,rr,m+1,r);}return ret;}int main(){int m,n;while (scanf("%d%d",&n,&m) != EOF){if (m == 0 && n == 0) break;memset(cl,0,sizeof(cl));memset(add,0,sizeof(add));memset(v,0,sizeof(v));build(1,1,n,2);for (int i = 0;i < m;i++){char s[5];int a,b,c;scanf("%s",s);if (s[0] == 'P'){scanf("%d%d%d",&a,&b,&c);update(1,a,b,c,1,n);}if (s[0] == 'Q'){memset(v,0,sizeof(v));scanf("%d%d",&a,&b);long long ans = query(1,a,b,1,n);for (int j = 0;j < 30;j++){if (ans & (1 << j)) v[j+1] = 1;}bool flag = 0;for (int j = 1;j <= 30;j++){if (v[j]){if (!flag){printf("%d",j);flag = 1;}elseprintf(" %d",j);}}printf("\n");}}}return 0;}
A - Hotel
题意:
一个旅馆有n间房间,最开始这些房间是空的。两种操作,第一种是a人问是否能住进来,这是查询是否有a个连续的房间,若有,则返回起点编号最小的区间的起点,并且把这些房间占用了。第二种操作是将起点为a,区间长度为
b的房间清空。
思路:
线段树的区间合并,非结构体版本,以后就用这个当板子。
主要用了ls,rs,ms三个变量表示当前区间的左连续长度,右连续长度和总连续长度。然后比较重要的函数是pushdown和pushup。特别注意横跨两个区间的长度是要单独讨论的。还得找题来做做。
代码:
#include <stdio.h>#include <string.h>#include <algorithm>using namespace std;#define lson l,mid,rt << 1#define rson mid + 1,r,rt << 1|1const int inf = 55555;int ls[inf << 2],rs[inf << 2],ms[inf << 2];int add[inf << 2];void pushdown(int rt,int len){if (add[rt] != -1){add[rt << 1] = add[rt << 1|1] = add[rt];ms[rt << 1] = ls[rt << 1] = rs[rt << 1] = add[rt] ? 0 : len - (len >> 1);ms[rt << 1|1] = ls[rt << 1|1] = rs[rt << 1|1] = add[rt] ? 0 : (len >> 1);add[rt] = -1;}}void pushup(int rt,int len){ls[rt] = ls[rt << 1];rs[rt] = rs[rt << 1|1];if (ls[rt] == len - (len >> 1)) ls[rt] += ls[rt << 1|1];if (rs[rt] == (len >> 1))rs[rt] += rs[rt << 1];ms[rt] = max(ms[rt << 1],ms[rt << 1|1]);ms[rt] = max(ms[rt],rs[rt << 1] + ls[rt << 1|1]);}void build(int l,int r,int rt){add[rt] = -1;ls[rt] = rs[rt] = ms[rt] = r - l + 1;if (l == r) return;int mid = (l + r) >> 1;build(lson);build(rson);}void update(int ll,int rr,int k,int l,int r,int rt){if (l >= ll && r <= rr){add[rt] = k;ms[rt] = rs[rt] = ls[rt] = k ? 0 : (r - l + 1);return;}pushdown(rt,r - l + 1);int mid = (l + r) >> 1;if (ll <= mid) update(ll,rr,k,lson);if (rr > mid) update(ll,rr,k,rson);pushup(rt,r-l+1);}int query(int w,int l,int r,int rt){if (l == r) return l;pushdown(rt,r - l + 1);int mid = (l + r) >> 1;if (ms[rt << 1] >= w)return query(w,lson);else if (rs[rt << 1] + ls[rt << 1|1] >= w)return mid - rs[rt << 1] + 1;elsereturn query(w,rson);}int main(){int m,n;scanf("%d%d",&n,&m);build(1,n,1);while (m--){int a,b,c;scanf("%d",&a);if (a == 1){scanf("%d",&b);if (ms[1] < b)printf("0\n");else{int t = query(b,1,n,1);printf("%d\n",t);update(t,t+b-1,1,1,n,1);}}else{scanf("%d%d",&b,&c);update(b,b + c - 1,0,1,n,1);}}return 0;}