这个题是个线段树的练手题,想当年调试这个题的时候调得要吐血了。。
当年总结出来的经验是:随时随地释放标记。但是当年的标记有个很大的bug,就是我只是释放标记,没有更新线段树。因此每次访问一个节点时还得看看是否有标记没有释放。这几天为了写coci2011 sequence,我只好重新开始写线段树。今天突然想到,释放标记时更新线段树,那么query就可以直接取值了,而modify则只需push一遍。push也简单了很多,两个赋值足以,代码量瞬间精简。
#include <stdio.h>
#ifndef ONLINE_JUDGE
#include <memory.h>
#endif
#define maxn 131072
int st[maxn * 2];
int mark[maxn * 2];
inline void push(int t, int m)
{
mark[t] = st[t] = m;
}
inline void clear(int t)
{
static int i;
int bak = t, find = 0;
for (; t; t >>= 1)
if (mark[t])
find = t;
if (!find) return;
i = mark[find], mark[find] = 0, st[bak] = i;
for (; bak != find; bak >>= 1)
push (bak ^ 1, i), st[bak] = i, mark[bak] = 0;
}
int query(int l, int r)
{
int ans = 0;
for (clear(l += maxn - 1), clear(r += maxn + 1); l ^ r ^ 1; l >>= 1, r >>= 1)
{
if (~l & 1) ans |= st[l ^ 1];
if ( r & 1) ans |= st[r ^ 1];
}
return ans;
}
int modify(int l, int r, int c)
{
c = 1 << c;
for (clear(l += maxn - 1), clear(r += maxn + 1); l ^ r ^ 1; l >>= 1, r >>= 1)
{
if (~l & 1) push (l ^ 1, c);
if ( r & 1) push (r ^ 1, c);
st[l >> 1] = st[l ^ 1] | st[l], st[r >> 1] = st[r ^ 1] | st[r];
}
for (l >>= 1; l; l >>= 1)
st[l] = st[l << 1] | st[l << 1 | 1];
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("2777.in" , "r", stdin);
freopen("2777.out", "w", stdout);
#endif
int l, t, o, a, b;
char cmd[5];
scanf("%d%d%d", &l, &t, &o);
for (a = l + maxn; a; --a)
st[a] = 2;
for (; o; --o)
{
scanf("%s%d%d", cmd, &a, &b);
if (a > b)
t = a, a = b, b = t;
if (cmd[0] == 'C')
scanf("%d", &t), modify(a, b, t);
else
printf("%d\n", __builtin_popcount(query(a, b)));
}
return 0;
}