HDOJ1540 Tunnel Warfare 线段树区间合并

HDOJ 1540

题目大意:给定两个整数N,M, 其中N表示一共有N个村庄,M代表有M次操作,操作有以下:

1.    D x  销毁村庄x

2.    Q x  询问与村庄x相邻的村庄总数

3.    R     最近一次销毁的村庄得到重建

问题分析:

对于N个村庄,可以建立一颗线段树,维护最大连续区间长度,操作分析:

  1. 在线段树上找到x节点,并将x节点“销毁”(村庄x被销毁),然后分别更新与x节点(村庄x)相关联的节点值(这里指左右连续区间的长度)
  2. 对于询问操作,显然这里要求返回的是存在x的最大左右连续区间长度和
  3. 将村庄x恢复(具体到重置线段的覆盖标志),并更新与村庄x相关联的最大连续区间和

具体实现:

对于有N个村庄,可以建立区间为[1, N]的线段树,维护最大连续区间长度,节点里有这些信息需要维护:最大左连续区间长度,最大右连续区间长度,总对大连续区间长度,覆盖标志,每次PushUp都要将左右子区间进行合并,加入lazy-tag优化时间复杂度(简单来说就是将更新延迟到下一次询问或者需要更新的时候),对于R操作,因为该操作的对象是最近一次销毁的村庄,因此在每一次 D x 操作以后就将 x 进栈,等到 R 操作时就将栈顶弹出,于是操作对象就转移到栈顶元素

代码:

  1 #include <stack>
  2 #include <cstdio>
  3 using namespace std;
  4 
  5 #define lson l, m, rt<<1
  6 #define rson m+1, r, rt<<1|1
  7 
  8 const int maxn = 50000;
  9 
 10 char cmd[5];
 11 stack <int> st;
 12 int n, mNum, a;
 13 int lsum[maxn*3], rsum[maxn*3], sum[maxn*3], cover[maxn*3];
 14 
 15 int Max(int x, int y)
 16 {
 17     return (x>y ? x:y);
 18 }/* Max */
 19 
 20 void BuildTree(int l, int r, int rt)
 21 {
 22     cover[rt] = -1;
 23     lsum[rt] = rsum[rt] = sum[rt] = r-l+1;
 24     
 25     if (l == r)
 26         return ;
 27     
 28     int m = (l+r)>>1;
 29     BuildTree(lson);
 30     BuildTree(rson);
 31 }/* BuildTree */
 32 
 33 void PushDown(int rt, int k)
 34 {
 35     if (cover[rt] != -1)
 36     {
 37         cover[rt<<1] = cover[rt<<1|1] = cover[rt];
 38         lsum[rt<<1] = rsum[rt<<1] = sum[rt<<1] = cover[rt] ? 0:k-(k>>1);
 39         lsum[rt<<1|1] = rsum[rt<<1|1] = sum[rt<<1|1] = cover[rt] ? 0:(k>>1);
 40         cover[rt] = -1;
 41     }
 42 }/* PushDown */
 43 
 44 int Query(int p, int l, int r, int rt)
 45 {
 46     if (sum[rt]==0 || sum[rt]==r-l+1 || l==r)
 47         return sum[rt];
 48     
 49     PushDown(rt, r-l+1);
 50     
 51     int m = (l+r)>>1;
 52     if (p <= m)
 53     {
 54         if (p > m-rsum[rt<<1])
 55             return rsum[rt<<1]+Query(m+1, rson);
 56         else
 57             return Query(p, lson);
 58     }
 59     else
 60     {
 61         if (p <= m+lsum[rt<<1|1])
 62             return lsum[rt<<1|1]+Query(m, lson);
 63         else
 64             return Query(p, rson);
 65     }
 66 }/* Query */
 67 
 68 void PushUp(int rt, int k)
 69 {   /* 左右子区间合并 */ 
 70     lsum[rt] = lsum[rt<<1];
 71     rsum[rt] = rsum[rt<<1|1];
 72     
 73     if (lsum[rt] == k-(k>>1))
 74         lsum[rt] += lsum[rt<<1|1];
 75     if (rsum[rt] == (k>>1))
 76         rsum[rt] += rsum[rt<<1];
 77     
 78     sum[rt] = Max(rsum[rt<<1]+lsum[rt<<1|1], Max(sum[rt<<1], sum[rt<<1|1]));
 79 }/* PushUp */
 80 
 81 void UpData(int p, int c, int l, int r, int rt)
 82 {
 83     if (l == r)
 84     {
 85         lsum[rt] = rsum[rt] = sum[rt] = c ? 0:r-l+1;
 86         cover[rt] = c;
 87         
 88         return ;
 89     }/* End of If */
 90     
 91     PushDown(rt, r-l+1);
 92     
 93     int m = (l+r)>>1;
 94     if (p <= m)
 95         UpData(p, c, lson);
 96     else
 97         UpData(p, c, rson);
 98     
 99     PushUp(rt, r-l+1);
100 }/* UpData */
101 
102 int main()
103 {
104     while (~scanf("%d %d", &n, &mNum))
105     {
106         BuildTree(1, n, 1);
107         
108         while (!st.empty())
109             st.pop();
110         
111         for (int i=1; i<=mNum; ++i)
112         {
113             scanf("%s", cmd);
114             if (cmd[0] == 'Q')
115             {
116                 scanf("%d", &a);
117                 printf("%d\n", Query(a, 1, n, 1));
118             }
119             else if (cmd[0] == 'D')
120             {
121                 scanf("%d", &a);
122                 UpData(a, 1, 1, n, 1);
123                 st.push(a);
124             }
125             else
126             {
127                 a = st.top();
128                 st.pop();
129                 UpData(a, 0, 1, n, 1);
130             }
131         }/* End of For */
132     }/* End of While */    
133     
134     return 0;
135 }
原文地址:https://www.cnblogs.com/yewei/p/2494324.html