其他分享
首页 > 其他分享> > P2894 [USACO08FEB]Hotel G

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