hdu4831 Scenic Popularity(线段树)

  题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=4831

  题目大概意思就是有多个风景区和休息区,每个风景区有热度,休息区的热度与最接近的分景区的热度相同,题目要求求出小于等于给定热度值的风景区和休息区的个数。显然如果直接暴力的话,复杂度为O(TKN),达到10^9次方数量级,复杂度过高,对于这种问答的题目,最一般的思路其实是线段树,线段树更改和查询的时间复杂度均为O(logn),所以如果用线段树的话,这道题目的复杂度为O(TKlogH),达到10^5左右的数量级,这个复杂度可以满足题目要求。

  线段树的实现一般用完全二叉树来实现,每个节点都可以看做是一段"线段"或者某个”范围“(x,y],这道题目节点表示的”范围“就是某段景区热度值(x,y],同时节点还记录了在该”范围“中包含的景区和休息区的个数,所以树的叶子节点就是等于某个热度值的景区和休息区的个数。线段树的定义如下:

#define MAX_SIZE 100000
typedef struct _tree
{
    int count;
    int left, right;
}TreeNode;
TreeNode tree[9 * MAX_SIZE + 5];
void Init(int x, int left, int right)
{
    tree[x].count = 0;
    tree[x].left = left;
    tree[x].right = right;
    if (left + 1 == right)
        return;
    Init(x << 1, left, (left + right) >> 1);
    Init((x << 1) + 1, (left + right) >> 1, right);
}
void Update(int x, int coord, int count)
{
    int left = tree[x].left;
    int right = tree[x].right;
    int mid = (left + right) >> 1;
    if (left + 1 == right)    
    {
        tree[x].count += count;
        return;
    }    
    if (coord <= mid)
        Update(x << 1, coord, count);
    else
        Update((x << 1) + 1, coord, count);
    tree[x].count += count;
}
int Query(int x, int coord)
{
    int left = tree[x].left;
    int right = tree[x].right;
    int mid = (left + right) >> 1;
    if (left + 1 == right)
        return tree[x].count;
    if (coord <= mid)
        return Query(x << 1, coord);
    else if (coord > mid)
        return tree[x << 1].count + Query((x << 1) + 1, coord);
}

  每次更新某个景区的热度值时,受影响的是该景区和离该景区近的休息区的热度值,其它的景区和热度值是保持不变的,只要预处理离每个景区近的休息区的个数,就可以在更新某个景区的热度值后立马得到哪些景区和休息区的热度值受到影响,从而更新线段树。不过需要注意的是某个休息区同时与两个景区距离相同的情况。我的方法是对每个景区和休息区设置两个变量li和ri,如果是景区,li表示向前所能影响的最前的休息区,ri表示向后所能影响的最后的休息区;如果是休息区,并且有两个风景区到该休息区的距离相等,li和ri分别表示这两个风景区。有个这两个变量,对于给定的风景区,就能直接计算该风景区所影响的休息区个数。

typedef struct _xh
{
    int x;
    int h;
    int li, ri;
}XH;
XH data[10005];

int GetCount(int x)
{
    int cnt = data[x].ri - data[x].li + 1;
    if (data[x].li < x && data[data[x].li].li != -1 && data[data[data[x].li].li].h >= data[x].h)
        cnt--;
    if (data[x].ri > x && data[data[x].ri].ri != -1 && data[data[data[x].ri].ri].h > data[x].h)
        cnt--;
    return cnt;
}

  有了上面的分析,对于给定的热度值获取小于等于这个热度值的景区和休息区的个数就简单了,直接查询线段树就可以了。

  具体代码如下:

  1 #include <stdio.h>
  2 #include <string.h>
  3 
  4 #define MAX_SIZE 100000
  5 typedef struct _tree
  6 {
  7     int count;
  8     int left, right;
  9 }TreeNode;
 10 TreeNode tree[9 * MAX_SIZE + 5];
 11 typedef struct _xh
 12 {
 13     int x;
 14     int h;
 15     int li, ri;
 16 }XH;
 17 XH data[10005];
 18 
 19 typedef struct _qy
 20 {
 21     char op;
 22     int x, h;
 23 }QY;
 24 QY qy[105];
 25 
 26 void Init(int x, int left, int right)
 27 {
 28     tree[x].count = 0;
 29     tree[x].left = left;
 30     tree[x].right = right;
 31     if (left + 1 == right)
 32         return;
 33     Init(x << 1, left, (left + right) >> 1);
 34     Init((x << 1) + 1, (left + right) >> 1, right);
 35 }
 36 void Update(int x, int coord, int count)
 37 {
 38     int left = tree[x].left;
 39     int right = tree[x].right;
 40     int mid = (left + right) >> 1;
 41     if (left + 1 == right)    
 42     {
 43         tree[x].count += count;
 44         return;
 45     }    
 46     if (coord <= mid)
 47         Update(x << 1, coord, count);
 48     else
 49         Update((x << 1) + 1, coord, count);
 50     tree[x].count += count;
 51 }
 52 int Query(int x, int coord)
 53 {
 54     int left = tree[x].left;
 55     int right = tree[x].right;
 56     int mid = (left + right) >> 1;
 57     if (left + 1 == right)
 58         return tree[x].count;
 59     if (coord <= mid)
 60         return Query(x << 1, coord);
 61     else if (coord > mid)
 62         return tree[x << 1].count + Query((x << 1) + 1, coord);
 63 }
 64 int GetCount(int x)
 65 {
 66     int cnt = data[x].ri - data[x].li + 1;
 67     if (data[x].li < x && data[data[x].li].li != -1 && data[data[data[x].li].li].h >= data[x].h)
 68         cnt--;
 69     if (data[x].ri > x && data[data[x].ri].ri != -1 && data[data[data[x].ri].ri].h > data[x].h)
 70         cnt--;
 71     return cnt;
 72 }
 73 int main(void)
 74 {
 75     int t, n, k, i, j, pl, pr, cnt, max, x, h, cntpre, cntnext, cntnew, cntnpre, cntnnext;
 76     char op;
 77 
 78     scanf("%d", &t);
 79     for (i = 0; i < t; i++)
 80     {
 81         max = 0;
 82         memset(data, -1, sizeof(data));
 83         scanf("%d", &n);    
 84         for (j = 0; j < n; j++)
 85         {
 86             scanf("%d%d", &data[j].x, &data[j].h);
 87             if (max < data[j].h)
 88                 max = data[j].h;
 89         }
 90         scanf("%d", &k);
 91         for (j = 0; j < k; j++)
 92         {
 93             scanf("%1s", &qy[j].op);    
 94             if (qy[j].op == 'Q')
 95                 scanf("%d", &qy[j].h);
 96             else
 97                 scanf("%d%d", &qy[j].x, &qy[j].h);
 98             if (max < qy[j].h)
 99                 max = qy[j].h;
100         }
101         pl = pr = 0;
102         while (pl < n && !data[pl].h)
103             pl++;
104         data[pl].li = 0;  
105         pr = pl + 1;
106         while (pl < n)
107         {
108             while (pr < n && !data[pr].h)    
109                 pr++;
110             if (pr == n)
111                 break;
112             if (pl + 1 == pr)
113             {
114                 data[pl].ri = pl;
115                 data[pr].li = pr;
116             }
117             else
118             {
119                 j = pl + 1;
120                 while (j < pr)    
121                     if (data[j]. x - data[pl].x < data[pr].x - data[j].x)
122                     {
123                         data[pl].ri = j;
124                         data[pr].li = j + 1;
125                         j++;
126                     }
127                     else if (data[j]. x - data[pl].x == data[pr].x - data[j].x)
128                     {
129                         data[pl].ri = data[pr].li = j;
130                         data[j].li = pl;
131                         data[j].ri = pr;
132                         break;
133                     }
134                     else
135                     {
136                         data[pr].li = j;
137                         data[pl].ri = j - 1;
138                         break;
139                     }
140             }
141             pl = pr++;
142         }
143         if (pl < n)
144             data[pl].ri = n - 1;
145         Init(1, 0, max);
146         for (j = 0; j < n; j++)
147             if (data[j].h)
148             {
149                 cnt = GetCount(j);
150                 Update(1, data[j].h, cnt);
151             }
152         printf("Case #%d:\n", i + 1);
153         for (j = 0; j < k; j++)
154             if (qy[j].op == 'Q')
155                 printf("%d\n", Query(1, qy[j].h));
156             else
157             {
158                 x = qy[j].x;
159                 h = qy[j].h;
160                 cnt = GetCount(x);                
161                 Update(1, data[x].h, -cnt);
162                 cntpre = cntnext = cntnpre = cntnnext = 0;
163                 if (data[x].li < x && data[data[x].li].li != -1)
164                     cntpre = GetCount(data[data[x].li].li);
165                 if (data[x].ri > x && data[data[x].ri].ri != -1)
166                     cntnext = GetCount(data[data[x].ri].ri);
167                 data[x].h = h;
168                 cntnew = GetCount(x);
169                 Update(1, data[x].h, cntnew);
170                 if (data[x].li < x && data[data[x].li].li != -1)
171                     cntnpre = GetCount(data[data[x].li].li);
172                 if (data[x].ri > x && data[data[x].ri].ri != -1)
173                     cntnnext = GetCount(data[data[x].ri].ri);
174                 if (cntpre != cntnpre)
175                     Update(1, data[data[data[x].li].li].h, cntnpre - cntpre);
176                 if (cntnext != cntnnext)
177                     Update(1, data[data[data[x].ri].ri].h, cntnnext - cntnext);
178             }
179     }
180     return 0;
181 }
View Code
posted @ 2014-06-02 16:57  在于思考  阅读(756)  评论(0编辑  收藏  举报