hdu-4533(线段树+区间合并)
约会安排
跟hdu-1540(线段树+区间合并) - 魏老6 - 博客园 (cnblogs.com)是一样,但是要写两个线段树。
线段树维护,最长前缀pre,最长后缀suf,以及最大连续连续区间sum。
1代表空,0代表时间被占了
还有几个注意事项:
当是DS时,只能查询和修改屌丝树;
当是NS时,先判断屌丝树能不能修改,能的话,屌丝和女神都要修改;屌丝树不能修改,则判断女神树能不能修改,能的话俩棵树都要修改。
详细见代码:
#define _CRT_SECURE_NO_WARNINGS 1
#include<algorithm>
#include<fstream>
#include<iostream>
#include<cstdio>
#include<deque>
#include<string>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<bitset>
#include<unordered_map>
using namespace std;
#define INF 100000
#define MAXN 310000
#define N 110010
#define M 1e9+7
#define endl '\n'
#define exp 1e-8
#define lc p << 1
#define rc p << 1|1
#define lowbit(x) ((x)&-(x))
const double pi = acos(-1.0);
typedef long long LL;
typedef unsigned long long ULL;
inline ULL read() {
ULL x = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch>'9') {
if (ch == '-')
f = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 1) + (x << 3) + (ch ^ 48);
ch = getchar();
}
return x * f;
}
void print(ULL x) {
if (x > 9)print(x / 10);
putchar(x % 10 ^ 48);
}
struct tree
{
int l, r, pre, suf,sum,tag;
}tr_1[N*4],tr_2[N*4];
int t, n, m;
void pushup(tree tr[],int p)
{
int len = tr[p].r - tr[p].l +1;
tr[p].sum = tr[lc].suf + tr[rc].pre;
tr[p].pre = tr[lc].pre;
tr[p].suf = tr[rc].suf;
if (tr[lc].pre == len - (len >> 1))
tr[p].pre = tr[lc].pre + tr[rc].pre;
if (tr[rc].suf == len >> 1)
tr[p].suf = tr[lc].suf + tr[rc].suf;
tr[p].sum = max(tr[p].sum, max(tr[lc].sum, tr[rc].sum)); //tr[p].sum 在中间连续的区间和左右结点的sum取最大
}
void pushdown(tree tr[], int p)
{
if (tr[p].tag == 1) //1代表学习,即有时间
{
tr[lc].pre = tr[lc].suf = tr[lc].sum = tr[lc].r - tr[lc].l + 1;
tr[rc].pre = tr[rc].suf = tr[rc].sum = tr[rc].r - tr[rc].l + 1;
tr[lc].tag = tr[rc].tag = 1;
tr[p].tag = 0;
}
else if(tr[p].tag==-1)//-1代表时间被占
{
tr[lc].pre = tr[lc].suf = tr[lc].sum = 0;
tr[rc].pre = tr[rc].suf = tr[rc].sum = 0;
tr[lc].tag = tr[rc].tag = -1;
tr[p].tag = 0;
}
}
void build(tree tr[], int p, int l, int r)
{
tr[p].tag = 0; //我是sb,这里一定要写
tr[p].l = l, tr[p].r = r;
if (l == r)
{
tr[p].pre = tr[p].suf = tr[p].sum = 1;
return;
}
int m = l + r >> 1;
build(tr, lc, l, m);
build(tr, rc, m + 1, r);
pushup(tr,p);
}
void update(tree tr[], int p, int x, int y, int c) //区间修改
{
if (x <= tr[p].l && tr[p].r <= y)
{
if (c==1)
{
tr[p].pre = tr[p].suf = tr[p].sum = tr[p].r - tr[p].l + 1;
tr[p].tag = 1;
}
else
{
tr[p].pre = tr[p].suf = tr[p].sum = 0;
tr[p].tag = -1;
}
return;
}
pushdown(tr, p);
int m = tr[p].l + tr[p].r >> 1;
if (x <= m)update(tr, lc, x, y, c);
if (y > m)update(tr, rc, x, y, c);
pushup(tr, p);
}
int query(tree tr[], int p, int x)
{
if (tr[p].l == tr[p].r)return tr[p].l;
pushdown(tr,p);
int m = tr[p].l + tr[p].r >> 1;
if (tr[lc].sum >= x)return query(tr, lc, x); //左边有,走左边
else if (tr[lc].suf+tr[rc].pre>=x)return tr[lc].r - tr[lc].suf+1; //左边没有,判断中间是否有
else return query(tr, rc, x); //实在不行走右边
}
int main()
{
int cnt = 0;
t = read();
while (t--)
{
cnt++;
n = read(), m = read();
build(tr_1, 1, 1, n);
build(tr_2, 1, 1, n);
printf("Case %d:\n", cnt);
while (m--)
{
string s;
cin >> s;
if (s == "DS")
{
int x = read();
if (tr_1[1].sum >= x)
{
int ans = query(tr_1, 1, x);
printf("%d,let's fly\n", ans);
update(tr_1, 1, ans, ans + x - 1, -1);
}
else puts("fly with yourself");
}
else if (s == "NS")
{
int x = read();
if (tr_1[1].sum >= x)
{
int ans = query(tr_1, 1, x);
printf("%d,don't put my gezi\n", ans);
update(tr_1, 1, ans, ans + x - 1, -1);
update(tr_2, 1, ans, ans + x - 1, -1);
}
else if (tr_2[1].sum >= x)
{
int ans = query(tr_2, 1, x);
printf("%d,don't put my gezi\n", ans);
update(tr_1, 1, ans, ans + x - 1, -1);
update(tr_2, 1, ans, ans + x - 1, -1);
}
else puts("wait for me");
}
else
{
int x = read(), y = read();
update(tr_1, 1, x, y, 1);
update(tr_2, 1, x, y, 1);
puts("I am the hope of chinese chengxuyuan!!");
}
}
}
return 0;
}