A-敌兵布阵
线段树的单点修改和查询区间总和操作
#include <iostream>
using namespace std;
const int N = 5e4 + 10;
struct Node
{
int l, r;
int sum;
}tr[4 * N];
int w[N];
void pushup(int u)
{
tr[u].sum = tr[u << 1].sum +tr[u << 1 | 1].sum;
}
void build(int u, int l, int r)
{
if (l == r)
{
tr[u] = {l, r, w[l]};
return;
}
tr[u] = {l, r};
int mid = l + r >> 1;
build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
pushup(u);
}
int query(int u, int l, int r)
{
if (l <= tr[u].l && tr[u].r <= r)
return tr[u].sum;
int sum = 0;
int mid = tr[u].l + tr[u].r >> 1;
if (l <= mid) sum += query(u << 1, l, r);
if (r > mid) sum += query(u << 1 | 1, l , r);
return sum;
}
void modify(int u, int x, int v)
{
if (tr[u].l == tr[u].r)
{
tr[u].sum += v;
return;
}
int mid = tr[u].l + tr[u].r >> 1;
if (x <= mid) modify(u << 1, x, v);
else modify(u << 1 | 1, x, v);
pushup(u);
}
int main()
{
int T, n;
cin >> T;
for (int i = 1; i <= T; i ++)
{
printf("Case %d:\n", i);
cin >> n;
for (int i = 1; i <= n; i ++)
scanf("%d", &w[i]);
build(1, 1, n);
char op[10];
while(scanf("%s", op), op[0] != 'E')
{
if (op[0] == 'Q')
{
int x, y;
scanf("%d%d", &x, &y);
printf("%d\n", query(1, x, y));
}
if (op[0] == 'A')
{
int x, v;
scanf("%d%d", &x, &v);
modify(1, x, v);
}
if (op[0] == 'S')
{
int x, v;
scanf("%d%d", &x, &v);
modify(1, x, -v);
}
}
}
return 0;
}
B - I Hate It
线段树的单点修改和查询区间最大值操作
#include <iostream>
using namespace std;
int n, m;
const int N = 200000 + 10;
struct Node
{
int l, r, v;
}tr[4 * N];
int w[N];
void pushup(int u)
{
tr[u].v = max(tr[u << 1].v, tr[u << 1 | 1].v);
}
void build(int u, int l, int r)
{
if (l == r)
{
tr[u] = {l, r, w[l]};
return;
}
tr[u] = {l, r};
int mid = l + r >> 1;
build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
pushup(u);
}
int query(int u, int l, int r)
{
if (l <= tr[u].l && r >= tr[u].r)
{
return tr[u].v;
}
int mid = tr[u].l + tr[u].r >> 1;
int res = -99999;
if (l <= mid) res = max(res, query(u << 1, l, r));
if (r > mid) res = max(res, query(u << 1 | 1, l, r));
return res;
}
void modify(int u, int x, int v)
{
if (tr[u].l == tr[u].r)
{
tr[u].v = v;
return;
}
int mid = tr[u].l + tr[u].r >> 1;
if (x <= mid) modify(u << 1, x, v);
if (x > mid) modify(u << 1 | 1, x, v);
pushup(u);
}
int main()
{
while (cin >> n >> m)
{
for (int i = 1; i <= n; i ++)
scanf("%d", &w[i]);
build(1, 1, n);
while(m --)
{
char op[3]; int x, y;
scanf("%s%d%d", op, &x, &y);
if (op[0] == 'Q')
printf("%d\n", query(1, x, y));
if (op[0] == 'U')
modify(1, x, y);
}
}
return 0;
}
C - A Simple Problem with Integers
线段树懒标记和查询区间和
#include <iostream>
#include <cstdio>
using namespace std;
const int N = 100000 + 10;
int n, m;
typedef long long LL;
int w[N];
struct Node
{
int l, r;
LL sum, add;
}tr[4 * N];
void pushup(int u)
{
tr[u].sum = tr[u << 1].sum + tr[u << 1 | 1].sum;
}
void pushdown(int u)
{
if (tr[u].add)
{
Node &root = tr[u];
Node &l = tr[u << 1];
Node &r = tr[u << 1 | 1];
l.add += root.add, l.sum += (l.r - l.l + 1) * root.add;
r.add += root.add, r.sum += (r.r - r.l + 1) * root.add;
root.add = 0;
}
}
void build(int u, int l, int r)
{
if (l == r)
{
tr[u] = {l, r, w[l], 0};
return;
}
tr[u] = {l, r};
int mid = l + r >> 1;
build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
pushup(u);
}
LL query(int u, int l, int r)
{
if (l <= tr[u].l && tr[u].r <= r)
return tr[u].sum;
pushdown(u);
LL res = 0;
int mid = tr[u].l + tr[u].r >> 1;
if (l <= mid) res += query(u << 1, l, r);
if (r > mid) res += query(u << 1 | 1, l, r);
return res;
}
void modify(int u, int l, int r, int v)
{
if (l <= tr[u].l && tr[u].r <= r)
{
tr[u].add += v;
tr[u].sum += (LL)(tr[u].r - tr[u].l + 1) * v;
return;
}
pushdown(u);
int mid = tr[u].l + tr[u].r >> 1;
if (l > mid) modify(u << 1 | 1, l, r, v);
else if (r <= mid) modify(u << 1, l, r, v);
else
{
modify(u << 1 | 1, l, r, v);
modify(u << 1, l, r, v);
}
pushup(u);
}
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i ++ ) scanf("%d", &w[i]);
build(1, 1, n);
char op[2];
int l, r, d;
while (m -- )
{
scanf("%s%d%d", op, &l, &r);
if (*op == 'C')
{
scanf("%d", &d);
modify(1, l, r, d);
}
else printf("%lld\n", query(1, l, r));
}
return 0;
}
D - Mayor’s posters
懒标记+离散化
题目大意:对于每组测试数据,在墙上张贴海报。先读入海报的数量n,然后给出n个l,r表示海报的区间范围。如果两张海报区间有重合,则对于重合部分,第二张海报会覆盖第一张。问最后可以看见多少张海报。
首先对于墙的长度为10000000,直接做显然是不行的,因为n最大为10000,因此可以将海报的左右端点离散化。考虑到先后张贴的三张海报区间为为1,10。1,3。5,10。如果直接离散化,得到的答案为2,显然是错误的,因为对于4这个点,并没有加入离散化。因此,每次对于一个海报的区间l,r,将l,r,r + 1三个点加入离散化。
对于每次加入一个海报,每次用值不同的懒标记标记。最后遍历查询每一个,查询有多少个不同的点即可。
#include <iostream>
#include <algorithm>
#include <vector>
#include <cstring>
#include <cstdio>
using namespace std;
const int N = 100010;
vector<int> xs;
int st[2 * N];
struct Segment
{
int x1, x2;
}seg[N];
struct Node
{
int l, r;
int v, add;
}tr[8 * N];
void pushdown(int u)
{
if (tr[u].add)
{
Node& root = tr[u], &left = tr[u << 1], &right = tr[u << 1 | 1];
left.add = root.add, right.add = root.add;
tr[u].add = 0;
}
}
void build(int u, int l, int r)
{
if (l == r)
{
tr[u] = {l, r, 0, 0};
return;
}
tr[u] = {l, r, 0, 0};
int mid = l + r >> 1;
build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
}
void modify(int u, int l, int r, int v)
{
if (l <= tr[u].l && tr[u].r <= r)
{
tr[u].add = v;
return;
}
int mid = tr[u].l + tr[u].r >> 1;
pushdown(u);
if (l <= mid) modify(u << 1, l, r, v);
if (r > mid) modify(u << 1 | 1, l, r, v);
}
int query(int u, int x)
{
if (tr[u].l == tr[u].r)
{
return tr[u].add;
}
pushdown(u);
int mid = tr[u].l + tr[u].r >> 1;
if (x <= mid) return query(u << 1, x);
else return query(u << 1 | 1, x);
}
int get(int x)
{
return lower_bound(xs.begin(), xs.end(), x) - xs.begin();
}
int main()
{
int T, n;
cin >> T;
while (T --)
{
memset(st, 0, sizeof st);
int cnt = 1;
scanf("%d", &n);
for (int i = 0; i < n; i ++)
{
scanf("%d%d", &seg[i].x1, &seg[i].x2);
xs.push_back(seg[i].x1), xs.push_back(seg[i].x2), xs.push_back(seg[i].x2 + 1);
}
sort(xs.begin(), xs.end());
xs.erase(unique(xs.begin(), xs.end()), xs.end());
build(1, 0, xs.size() - 1);
for (int i = 0; i < n; i ++)
{
int x1 = get(seg[i].x1);
int x2 = get(seg[i].x2);
modify(1, x1, x2, cnt ++);
}
for (int i = 0; i < n; i ++)
{
int x1 = get(seg[i].x1);
int x2 = get(seg[i].x2);
int v = query(1, x1);
// cout << v << endl;
st[v] = 1;
v = query(1, x2);
// cout << v << endl;
st[v] = 1;
v = query(1, x2 + 1);
st[v] = 1;
}
int len = xs.size();
int res = 0;
for (int i = 1; i <= 2 * len; i ++)
if (st[i]) res ++;
cout << res << endl;
}
return 0;
}
E - Just a Hook
G - Balanced Lineup
和A,B,C的思路相同,E是区间修改和查询总和。G是查询区间最大值和最小值。
H - Can you answer these queries?
题目大意:给定一个区间,将该区间的所有数都开根号。或者查询区间值的和。
首先,线段树结点存储区间的和,pushup操作为更新当前结点的和为左子节点的和+右子节点的和。
对于区间修改(开根号),我没有想到很好的方法。采用了每次遍历到每个叶节点进行修改操作然后pushup。为了防止TLE,因为值更新为1后再开根号没有意义,所以如果修改操作,向下递归时发现当前区间的所有数都是1,可以直接返回。(结点的和为区间长度)
区间查询为普通的区间查询。
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 1e5 + 10;
int n, m;
LL w[N];
struct Node
{
int l, r;
LL sum;
}tr[4 * N];
void pushup(int u)
{
tr[u].sum = tr[u << 1].sum + tr[u << 1 | 1].sum;
}
void build(int u, int l, int r)
{
if (l == r)
{
tr[u] = {l, r, w[l]};
return;
}
int mid = l + r >> 1;
tr[u] = {l ,r};
build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
pushup(u);
}
void modify(int u, int l, int r)
{
if (tr[u].r - tr[u].l + 1 == tr[u].sum)
return;
if (tr[u].l == tr[u].r)
{
tr[u].sum = (LL)sqrt(1.0 * tr[u].sum);
return;
}
int mid = tr[u].l + tr[u].r >> 1;
if (l <= mid)
modify(u << 1, l, r);
if (r > mid)
modify(u << 1 | 1, l, r);
pushup(u);
}
LL query(int u, int l, int r)
{
if (l <= tr[u].l &&tr[u].r <= r)
{
return tr[u].sum;
}
int mid = tr[u].l + tr[u].r >> 1;
LL res = 0;
if (l <= mid)
res += query(u << 1, l, r);
if (r > mid)
res += query(u << 1 | 1, l, r);
return res;
}
int main()
{
int T = 1;
while (scanf("%d", &n) != -1)
{
printf("Case #%d:\n", T ++);
for (int i = 1; i <= n; i ++)
scanf("%I64d", &w[i]);
build(1, 1, n);
scanf("%d", &m);
int t, x, y;
while (m --)
{
scanf("%d%d%d", &t, &x, &y);
if (y < x) swap(x, y);
if (t == 0)
modify(1, x, y);
else
printf("%I64d\n", query(1, x, y));
}
cout << endl;
}
return 0;
}
I - Tunnel Warfare
题目大致意思:抗日战争时期进行地道战,对于一系列点,敌人可以摧毁一个,我军也可以对上次摧毁的点进行修复。对于查询操作,查询包含这个点在内的最长的没有被摧毁序列的长度。
设如果某个点被摧毁,则值为0。否则值为1。
对于修复最近一次被摧毁的点,可以用栈来存储。
则问题变成了求包含某个点的最长1序列
线段树结点包含信息:左端点l,右端点r,该结点包含区间从左端点起从左到右的最长1序列长度lmax,该结点包含区间从右端点起从右到左的最长1序列长度rmax。
pushup操作即为(对于lmax来说):如果左子节点lmax小于左子节点区间长度,则父节点的lmax为左子节点 的lmax。否则表示左子节点lmax等于区间长度,即该左子节点区间全是1,则父节点的lmax为左子节点的整个区间+右子节点的lmax。
查询操作也是类似。比如:如果对于查询的这个点落在区间的中点左边,如果从该区间的中点至左的的连续1序列包含了查询点,则返回return tr[u << 1 | 1].lmax + tr[u << 1].rmax即可。否则递归查询左子结点。
#include <iostream>
using namespace std;
const int N = 5e4 + 10;
struct Node
{
int l, r;
int lmax, rmax;
}tr[4 * N];
int n, m;
int stk[N], top;
int x;
void pushup(int u)
{
Node &root = tr[u], &left = tr[u << 1], &right = tr[u << 1 | 1];
root.lmax = left.lmax;
if (left.r - left.l + 1 == left.lmax) root.lmax = left.lmax + right.lmax;
root.rmax = right.rmax;
if (right.r - right.l + 1 == right.rmax) root.rmax = right.rmax + left.rmax;
}
void build(int u, int l, int r)
{
if (l == r)
{
tr[u] = {l, l, 1, 1};
return;
}
tr[u] = {l, r};
int mid = l + r >> 1;
build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
pushup(u);
}
void modify(int u, int x, int v)
{
if (tr[u].l == tr[u].r)
{
tr[u].lmax = tr[u].rmax = v;
return;
}
int mid = tr[u].l + tr[u].r >> 1;
if (x <= mid) modify(u << 1, x, v);
else modify(u << 1 | 1, x, v);
pushup(u);
}
int query(int u, int x)
{
if (tr[u].l == tr[u].r || tr[u].lmax == tr[u].r - tr[u].l + 1)
{
return tr[u].lmax;
}
int mid = tr[u].l + tr[u].r >> 1;
// printf("mid: %d\n", mid);
if(x <= mid)
{
// printf("l: %d r: %d\n", tr[u << 1 | 1].lmax, tr[u << 1].rmax);
if (mid - x + 1 <= tr[u << 1].rmax)
{
return tr[u << 1 | 1].lmax + tr[u << 1].rmax;
}
else
{
return query(u << 1, x);
}
}
if (x > mid)
{
if (x - mid <= tr[u << 1 | 1].lmax)
return tr[u << 1].rmax + tr[u << 1 | 1].lmax;
else return query(u << 1 | 1, x);
}
}
int main()
{
while (~scanf("%d %d",&n,&m))
{
top = 0;
build(1, 1, n);
// for (int i = 1; i < N; i ++)
// {
// if (tr[i].l != 0)
// {
// printf("l:%d r:%d %d %d\n", tr[i].l, tr[i].r, tr[i].lmax, tr[i].rmax);
// }
// }
char op[4]; int x;
while (m --)
{
scanf("%s", op);
if (op[0] == 'D')
{
scanf("%d", &x);
stk[top ++] = x;
modify(1, x, 0);
}
else if (op[0] == 'Q')
{
scanf("%d", &x);
printf("%d\n", query(1, x));
}
else
{
if(x > 0)
{
x = stk[-- top];
modify(1, x, 1);
}
}
// for (int i = 1; i <= N; i ++)
// if (tr[i].l == 3 && tr[i].r == 4)
// {
// printf("tr.l,r : %d %d val: %d %d", tr[i].l, tr[i].r, tr[i].lmax, tr[i].rmax);
// puts("");
// }
}
}
return 0;
}
J - Assign the task
主要难点是如何建立区间。可以采用dfs,根据时间戳来确定线段树。
其中s数组记录先序遍历的时间戳,f数组记录后序遍历的时间戳,可知子节点的时间戳长度一定被包含在父节点的时间戳长度内。因此修改父节点的区间[s[u], f[u]]可以将其所以子节点一并修改。
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int N = 5e4 + 10;
int st[N];
int s[N], f[N], dfn;
int h[N], e[N], ne[N], idx;
struct Node
{
int l, r;
int add, val;
}tr[4 * N];
void pushdown(int u)
{
if (tr[u].add != -1)
{
Node &root = tr[u];
Node &l = tr[u << 1];
Node &r = tr[u << 1 | 1];
l.add = root.add, l.val = root.add;
r.add = root.add, r.val = root.add;
root.add = -1;
}
}
void build(int u, int l, int r)
{
if (l == r)
{
tr[u] = {l, r, -1, -1};
return;
}
tr[u] = {l, r, -1, -1};
int mid = l + r >> 1;
build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
}
int query(int u, int x)
{
if (tr[u].l == tr[u].r)
return tr[u].val;
pushdown(u);
int mid = tr[u].l + tr[u].r >> 1;
if (x <= mid) return query(u << 1, x);
return query(u << 1 | 1, x);
}
void modify(int u, int l, int r, int v)
{
if (l <= tr[u].l && tr[u].r <= r)
{
tr[u].add = v;
tr[u].val = v;
return;
}
pushdown(u);
int mid = tr[u].l + tr[u].r >> 1;
if (l <= mid) modify(u << 1 , l, r, v);
if (r > mid) modify(u << 1 | 1, l, r, v);
}
void dfs(int u)
{
s[u] = ++ dfn;
for (int i = h[u]; ~i; i = ne[i])
{
int j = e[i];
dfs(j);
}
f[u] = dfn;
}
void add(int a, int b)
{
e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
}
int main()
{
int T;
cin >> T;
for (int t = 1; t <= T; t ++)
{
printf("Case #%d:\n", t);
memset(h, -1, sizeof h);
idx = 0, dfn = 0;
memset(st, 0, sizeof st);
int n, m, u, v, root;
cin >> n;
build(1, 1, n);
for (int i = 0; i < n - 1; i ++)
{
cin >> u >> v;
add(v, u), st[u] = 1;
}
for (int i = 1; i <= n; i ++)
if (!st[i]) root = i;
dfs(root);
// cout << "起始和结束:";
// for (int i = 1; i <= n; i ++)
// cout << i << ' ' << s[i] << ' ' << f[i] << endl;
// cout << endl;
cin >> m;
while(m --)
{
// for (int i = 1; i <= n; i ++)
// cout << query(1, i) << ' ';
// cout << endl;
char op[5];
scanf("%s", op);
if (op[0] == 'C')
{
int x;
cin >> x;
cout << query(1, s[x]) << endl;
}
else
{
int x, y;
cin >> x >> y;
modify(1, s[x], f[x], y);
}
}
}
}
K - Transformation
对某段区间执行四种操作之一
- 都+c
- 都*c
- 都置为c
- 查询每个数字p次方的和
对于线段树的结点,懒标记add表示+操作,mul表示*操作,val表示置为某个数的操作。对于某个数,设其当前值为v * mul + add(当然刚刚建立完树时,mul为1,add为0),当传来乘法标记时,设其值为a,则该数变为(v * mul + add) * a,即add = add * a, mul = mul * a。当加法标记传来,设值为a,则mul不变,add = add + a。置值的标记传来,add变为0,mul变为1,即变成一开始的样子,val变成a。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 100010;
const int mod = 10007;
int n, m;
int w[N];
struct Node
{
int l, r;
long long sum[3];
int add, mul, val;
}tr[N * 4];
void pushup(int u)
{
tr[u].sum[0] = (tr[u << 1].sum[0] + tr[u << 1 | 1].sum[0]) % mod;
tr[u].sum[1] = (tr[u << 1].sum[1] + tr[u << 1 | 1].sum[1]) % mod;
tr[u].sum[2] = (tr[u << 1].sum[2] + tr[u << 1 | 1].sum[2]) % mod;
}
void eval(Node &t, int add, int mul, int val)
{
LL len = t.r - t.l + 1;
int a = mul;
int b = add;
if (val)
{
t.sum[0] = (LL)val % mod * len % mod;
t.sum[1] = (LL)val % mod * val % mod * len % mod;
t.sum[2] = (LL)val % mod * val % mod * val % mod * len % mod;
t.add = 0, t.mul = 1, t.val = val;
}
t.sum[2] = ((LL)a * a * a % mod * t.sum[2] % mod + 3 * (LL)a * a * b % mod * t.sum[1]
+ 3 * (LL)a * b * b % mod * t.sum[0] % mod + (LL)b * b * b % mod * len % mod) % mod;
t.sum[1] = ((LL)a * a * t.sum[1] % mod + 2 * (LL)a * b % mod * t.sum[0] % mod + (LL)b * b % mod * len % mod) % mod;
t.sum[0] = ((LL)t.sum[0] * mul + (LL)(t.r - t.l + 1) * add) % mod;
t.mul = (LL)t.mul * mul % mod;
t.add = ((LL)t.add * mul % mod + add) % mod;
}
void pushdown(int u)
{
eval(tr[u << 1], tr[u].add, tr[u].mul, tr[u].val);
eval(tr[u << 1 | 1], tr[u].add, tr[u].mul, tr[u].val);
tr[u].add = 0, tr[u].mul = 1, tr[u].val = 0;
}
void build(int u, int l, int r)
{
if (l == r) tr[u] = {l, r, 0, 0, 0, 0, 1, 0};
else
{
tr[u] = {l, r, 0, 0, 0, 0, 1, 0};
int mid = l + r >> 1;
build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
pushup(u);
}
}
void modify(int u, int l, int r, int add, int mul, int val)
{
if (tr[u].l >= l && tr[u].r <= r) eval(tr[u], add, mul, val);
else
{
pushdown(u);
int mid = tr[u].l + tr[u].r >> 1;
if (l <= mid) modify(u << 1, l, r, add, mul, val);
if (r > mid) modify(u << 1 | 1, l, r, add, mul, val);
pushup(u);
}
}
int query(int u, int l, int r, int p)
{
if (tr[u].l >= l && tr[u].r <= r) return tr[u].sum[p];
pushdown(u);
int mid = tr[u].l + tr[u].r >> 1;
int sum = 0;
if (l <= mid) sum = query(u << 1, l, r, p);
if (r > mid) sum = (sum + query(u << 1 | 1, l, r, p)) % mod;
return sum;
}
int main()
{
while (scanf("%d%d", &n, &m), n || m)
{
build(1, 1, n);
int t, x, y, c;
while (m -- )
{
scanf("%d%d%d%d", &t, &x, &y, &c);
if (t == 1) modify(1, x, y, c, 1, 0);
if (t == 2) modify(1, x, y, 0, c, 0);
if (t == 3) modify(1, x, y, 0, 1, c);
if (t == 4) printf("%d\n", query(1, x, y, c - 1) % mod);
}
}
return 0;
}
L - Vases and Flowers
线段树+二分,难度不大
#include <iostream>
#include <cstring>
using namespace std;
const int N = 1e5 + 10;
struct Node
{
int l, r;
int almax, atmax, armax; //屌丝
int blmax, btmax, brmax; //女神
int add;
}tr[4 * N];
void build(int u, int l, int r)
{
if (l == r)
{
tr[u] = {l, r, 1, 1, 1, 1, 1, 1, 0};
return;
}
int mid = l + r >> 1;
int len = r - l + 1;
tr[u] = {l, r, len, len, len, len, len, len, 0};
build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
}
void fun(int u, int v)
{
tr[u].add = v;
if (v == 3)
{
tr[u].almax = tr[u].atmax = tr[u].armax = tr[u].r - tr[u].l + 1;
tr[u].blmax = tr[u].btmax = tr[u].brmax = tr[u].r - tr[u].l + 1;
}
if (v == 1)
{
tr[u].almax = tr[u].atmax = tr[u].armax = 0;
tr[u].blmax = tr[u].btmax = tr[u].brmax = tr[u].r - tr[u].l + 1;
}
if (v == 2)
{
tr[u].almax = tr[u].atmax = tr[u].armax = 0;
tr[u].blmax = tr[u].btmax = tr[u].brmax = 0;
}
}
void pushdown(int u)
{
if (tr[u].add)
{
fun(u << 1, tr[u].add), fun(u << 1 | 1, tr[u].add);
tr[u].add = 0;
}
}
void pushup(int u)
{
Node &root = tr[u], &left = tr[u << 1], &right = tr[u << 1 | 1];
tr[u].almax = tr[u << 1].almax;
if (tr[u << 1].almax == left.r - left.l + 1)
tr[u].almax = left.r - left.l + 1 + tr[u << 1 | 1].almax;
tr[u].armax = tr[u << 1 | 1].armax;
if (tr[u << 1 | 1].armax == right.r - right.l + 1)
tr[u].armax = right.r - right.l + 1 + left.armax;
root.atmax = max(max(left.atmax, right.atmax), left.armax + right.almax);
tr[u].blmax = tr[u << 1].blmax;
if (tr[u << 1].blmax == left.r - left.l + 1)
tr[u].blmax = left.r - left.l + 1 + tr[u << 1 | 1].blmax;
tr[u].brmax = tr[u << 1 | 1].brmax;
if (tr[u << 1 | 1].brmax == right.r - right.l + 1)
tr[u].brmax = right.r - right.l + 1 + left.brmax;
root.btmax = max(max(left.btmax, right.btmax), left.brmax + right.blmax);
}
void modify(int u, int l, int r, int v)
{
if (l <= tr[u].l && tr[u].r <= r)
{
fun(u, v);
return;
}
pushdown(u);
int mid = tr[u].l + tr[u].r >> 1;
if (l <= mid) modify(u << 1, l, r, v);
if (r > mid) modify(u << 1 | 1, l, r, v);
pushup(u);
}
int query(int u, int x, int flag)
{
if (tr[u].l == tr[u].r)
{
return tr[u].l;
}
pushdown(u);
if (flag == 1)
{
if (tr[u << 1].atmax >= x)
return query(u << 1, x, 1);
else if (tr[u << 1].armax + tr[u << 1 | 1].almax >= x)
return tr[u << 1].r - tr[u << 1].armax + 1;
else return query(u << 1 | 1, x, 1);
}
if (flag == 2)
{
if (tr[u << 1].btmax >= x)
return query(u << 1, x, 2);
else if (tr[u << 1].brmax + tr[u << 1 | 1].blmax >= x)
return tr[u << 1].r - tr[u << 1].brmax + 1;
else return query(u << 1 | 1, x, 2);
}
}
int main()
{
int num;
int cas = 1;
cin >> num;
while (num --)
{
printf("Case %d:\n", cas ++);
int t, m;
scanf("%d%d", &t, &m);
build(1, 1, t);
char op[10];
int x, y;
while (m --)
{
scanf("%s", op);
if (op[0] == 'D')
{
scanf("%d", &x);
if (tr[1].atmax < x)
printf("fly with yourself\n");
else
{
int last = query(1, x, 1); //query(u, 长度,类型) 1表示屌丝
modify(1, last, x + last - 1, 1);
printf("%d,let's fly\n", last);
}
}
else if (op[0] == 'N') //女神
{
scanf("%d", &x);
if (tr[1].btmax < x)
printf("wait for me\n");
else
{
if (tr[1].atmax < x)
{
int last = query(1, x, 2); //query(u, 长度,类型) 2表示女生
modify(1, last, x + last - 1, 2);
printf("%d,don't put my gezi\n", last);
}
else
{
int last = query(1, x, 1);
modify(1, last, x + last - 1, 2);
printf("%d,don't put my gezi\n", last);
}
}
}
else
{
scanf("%d%d", &x, &y);
modify(1, x, y, 3); //3表示清0
printf("I am the hope of chinese chengxuyuan!!\n");
}
}
}
}