poj2777

这个题是个线段树的练手题,想当年调试这个题的时候调得要吐血了。。

当年总结出来的经验是:随时随地释放标记。但是当年的标记有个很大的bug,就是我只是释放标记,没有更新线段树。因此每次访问一个节点时还得看看是否有标记没有释放。这几天为了写coci2011 sequence,我只好重新开始写线段树。今天突然想到,释放标记时更新线段树,那么query就可以直接取值了,而modify则只需push一遍。push也简单了很多,两个赋值足以,代码量瞬间精简。


#include 
#ifndef ONLINE_JUDGE
#include 
#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;
}


你可能感兴趣的:(query,cmd,c)