P2894 [USACO08FEB]Hotel G
作者:互联网
题意就是维护整个序列最长连续01的位置,要求位置最左边,就是线段树最大连续子段和的查询操作稍作修改,每次查询分类讨论,如果左儿子内已经有满足题意的长度,就往左儿子找,如果左右凑起来有的话,就从左右凑起来,再查询右儿子有没有满足题意的长度.
#include<iostream>
#include<cstdio>
#define rep(i,j,k) for(register int i(j);i<=k;++i)
#define drp(i,j,k) for(register int i(j);i>=k;--i)
#define bug cout<<"~~~~~~~~~~~~~"<<'\n';
#define bugout(x) cout<<x<<endl;
using std::cin;
using std::cout;
typedef long long lxl;
template<typename T>
inline T max(T a, T b) {
return a > b ? a : b;
}
template<typename T>
inline T min(T a, T b) {
return a < b ? a : b;
}
inline char gt() {
static char buf[1 << 21], *p1 = buf, *p2 = buf;
return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++;
}
template <typename T>
inline void read(T &x) {
register char ch = gt();
x = 0;
int w(0);
while(!(ch >= '0' && ch <= '9'))w |= ch == '-', ch = gt();
while(ch >= '0' && ch <= '9')x = x * 10 + (ch & 15), ch = gt();
w ? x = ~(x - 1) : x;
}
template <typename T>
inline void out(T x, char cc) {
if(x < 0) x = -x, putchar('-');
char ch[20];
int num(0);
while(x || !num) ch[++num] = x % 10 + '0', x /= 10;
while(num) putchar(ch[num--]);
putchar(cc);
}
const int N = 5e4 + 79;
struct SegmentTree {
int sum[N << 2], lmax[N << 2], rmax[N << 2];
int lc[N << 2], rc[N << 2], tag[N << 2];
int rt, cnt;
inline void pushdown(int p, int L, int R) {
if(tag[p] == -1) return ;
int mid((L + R >> 1));
if(tag[p] == 1) {
sum[lc[p]] = lmax[lc[p]] = rmax[lc[p]] = mid - L + 1;
sum[rc[p]] = lmax[rc[p]] = rmax[rc[p]] = R - mid;
} else {
sum[lc[p]] = lmax[lc[p]] = rmax[lc[p]] = 0;
sum[rc[p]] = lmax[rc[p]] = rmax[rc[p]] = 0;
}
tag[lc[p]] = tag[rc[p]] = tag[p];
tag[p] = -1;
}
inline void pushup(int p, int L, int R) {
int mid(L + R >> 1);
if(sum[lc[p]] == mid - L + 1) {
lmax[p] = (mid - L + 1) + lmax[rc[p]];
} else {
lmax[p] = lmax[lc[p]];
}
if(sum[rc[p]] == R - mid) {
rmax[p] = (R - mid) + rmax[lc[p]];
} else {
rmax[p] = rmax[rc[p]];
}
sum[p] = max(max(sum[lc[p]], sum[rc[p]]), rmax[lc[p]] + lmax[rc[p]]);
}
inline void build(int &p, int L, int R) {
if(!p) p = ++cnt;
tag[p] = -1;
sum[p] = lmax[p] = rmax[p] = R - L + 1;
if(L == R) {
return ;
}
int mid(L + R >> 1);
build(lc[p], L, mid);
build(rc[p], mid + 1, R);
}
inline void change(int p, int L, int R, int ll, int rr, int val) {
if(ll <= L && rr >= R) {
if(val == 1) {
sum[p] = lmax[p] = rmax[p] = R - L + 1;
tag[p] = val;
} else {
sum[p] = lmax[p] = rmax[p] = 0;
tag[p] = val;
}
return;
}
pushdown(p, L, R);
int mid(L + R >> 1);
if(ll <= mid) change(lc[p], L, mid, ll, rr, val);
if(rr > mid) change(rc[p], mid + 1, R, ll, rr, val);
pushup(p, L, R);
}
inline int query(int p, int L, int R, int len) {
if(L == R) return L;
pushdown(p, L, R);
int mid(L + R >> 1);
if(sum[lc[p]] >= len) return query(lc[p], L, mid, len);
else if(rmax[lc[p]] + lmax[rc[p]] >= len) return mid - rmax[lc[p]] + 1; //左边的不够,加上右边够了
else if(sum[rc[p]] >= len) return query(rc[p], mid + 1, R, len);
return 0;
}
} S; //空闲的当1,求区间最长连续子段和
int n, m, k;
int main() {
// freopen("hotel.in", "r", stdin);
// freopen("hotel.out", "w", stdout);
read(n);
read(m);
S.build(S.rt, 1, n);
int x, p;
while(m--) {
read(k);
if(k == 1) {
read(p);
if(S.sum[S.rt] < p) {
out(0, '\n');
} else {
int po = S.query(S.rt, 1, n, p);
out(po, '\n');
S.change(S.rt, 1, n, po, po + p - 1, 0);
}
} else {
read(x);
read(p);
S.change(S.rt, 1, n, x, x + p - 1, 1);
}
}
return 0;
}
标签:lc,int,sum,Hotel,rmax,mid,USACO08FEB,rc,P2894 来源: https://www.cnblogs.com/QQ2519/p/15375298.html