这道题以前在学校内网刷过类似的,AC了后还挺有成就感,所以更详细的题解请看这里。
总的来说,就是用线段树维护区间最长连续0.因此我们要维护这么几个值:lmax:从当前区间左端点开始最长的连续0的长度;rmax:右端点开始最长连续0的长度;imax当前区间最长连续0的长度。有了这三个量,区间就可以合并了。
合并的方法看上面的链接,这里不再细讲了,这道题主要的区别查询。
查询是找长度为x的区间的位置,而不是在给定区间中查询最长连续区间。查询的具体步骤是这样的:
1.当前区间连续的最长长度比要找的len小,自然返回0。
2.否则我们看lmax[now],这个区间左起最长长度,如果大于len,就返回左端点就行啦。
3.因为题中说要使房间号尽量小,所以接下来应该看rmax[now << 1] + lmax[now << 1 |1]和len的关系,如果包含len,就返回r[now << 1] - rmax[now << 1] + 1.
4.最后就只能递归找右子区间了。
就因为上面的逻辑我刚开始想的不对,于是debug了快一个下午……
emacs格式,代码缩进很丑
1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #include<cstring> 5 #include<cmath> 6 #include<cstdlib> 7 #include<cctype> 8 #include<stack> 9 #include<queue> 10 #include<vector> 11 using namespace std; 12 #define enter puts("") 13 #define space putchar(‘ ‘) 14 #define Mem(a, x) memset(a, x, sizeof(a)) 15 #define rg register 16 typedef long long ll; 17 typedef double db; 18 const int INF = 0x3f3f3f3f; 19 const db eps = 1e-8; 20 const int maxn = 5e4 + 5; 21 inline ll read() 22 { 23 ll ans = 0; 24 char ch = getchar(), las = ‘ ‘; 25 while(!isdigit(ch)) las = ch, ch = getchar(); 26 while(isdigit(ch)) ans = (ans << 3) + (ans << 1) + ch - ‘0‘, ch = getchar(); 27 if(las == ‘-‘) ans = -ans; 28 return ans; 29 } 30 inline void write(ll x) 31 { 32 if(x < 0) putchar(‘-‘), x = -x; 33 if(x >= 10) write(x / 10); 34 putchar(x % 10 + ‘0‘); 35 } 36 37 38 int n, m; 39 40 struct Tree 41 { 42 int l, r, lzy; 43 int lmax, rmax, imax; 44 Tree operator + (const Tree& other)const 45 { 46 Tree ret; 47 ret.l = l; ret.r = other.r; 48 ret.lzy = -1; 49 ret.lmax = lmax; 50 if(lmax == r - l + 1) ret.lmax += other.lmax; 51 ret.rmax = other.rmax; 52 if(other.rmax == other.r - other.l + 1) ret.rmax += rmax; 53 ret.imax = max(max(imax, other.imax), rmax + other.lmax); 54 return ret; 55 } 56 }t[maxn << 2]; 57 void build(int L, int R, int now) 58 { 59 t[now].l = L; t[now].r = R; 60 t[now].lzy = -1; 61 t[now].lmax = t[now].rmax = t[now].imax = R - L + 1; 62 if(L == R) return; 63 int mid = (L + R) >> 1; 64 build(L, mid, now << 1); 65 build(mid + 1, R, now << 1 | 1); 66 } 67 void pushdown(int now) 68 { 69 if(t[now].lzy != -1) 70 { 71 t[now << 1].lmax = t[now << 1].rmax = t[now << 1].imax = (t[now << 1].r - t[now << 1].l + 1) * (t[now].lzy ^ 1); 72 t[now << 1 | 1].lmax = t[now << 1 | 1].rmax = t[now << 1 | 1].imax = (t[now << 1 | 1].r - t[now << 1 | 1].l + 1) * (t[now].lzy ^ 1); 73 t[now << 1].lzy = t[now << 1 | 1].lzy = t[now].lzy; 74 t[now].lzy = -1; 75 } 76 } 77 void update(int L, int R, int now, int flg) 78 { 79 if(L == t[now].l && R == t[now].r) 80 { 81 t[now].lmax = t[now].rmax = t[now].imax = (R - L + 1) * (flg ^ 1); 82 t[now].lzy = flg; return; 83 } 84 pushdown(now); 85 int mid = (t[now].l + t[now].r) >> 1; 86 if(R <= mid) update(L, R, now << 1, flg); 87 else if(L > mid) update(L, R, now << 1 | 1, flg); 88 else update(L, mid, now << 1, flg), update(mid + 1, R, now << 1 | 1, flg); 89 t[now] = t[now << 1] + t[now << 1 | 1]; 90 } 91 int query(int len, int now) 92 { 93 if(t[now].imax < len) return 0; 94 pushdown(now); 95 if(t[now].lmax >= len) return t[now].l; 96 else if(t[now << 1].imax >= len) return query(len, now << 1); 97 else if(t[now << 1].rmax + t[now << 1 | 1].lmax >= len) return t[now << 1].r - t[now << 1].rmax + 1; 98 else return query(len, now << 1 | 1); 99 } 100 101 int main() 102 { 103 n = read(); m = read(); 104 build(1, n, 1); 105 for(int i = 1; i <= m; ++i) 106 { 107 int d = read(); 108 if(d == 1) 109 { 110 int x = read(); 111 int ans = query(x, 1); 112 write(ans); enter; 113 if(ans) update(ans, ans + x - 1, 1, 1); 114 } 115 else 116 { 117 int L = read(), len = read(); 118 update(L, L + len - 1, 1, 0); 119 } 120 } 121 return 0; 122 }
原文地址:https://www.cnblogs.com/mrclr/p/9691656.html
时间: 2024-10-12 04:12:45