【HDU】 4831 Scenic Popularity 暴力模拟

Scenic Popularity

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 340    Accepted Submission(s): 110


Problem Description
  临近节日,度度熊们最近计划到室外游玩公园,公园内部包括了很多的旅游景点区和休息区,由于旅游景点很热门,导致景点区和休息区都聚集了很多人。所以度度熊在旅游之前想通过百度地图查看一下公园内各个地方的热门程度。
  假设所有景点区和休息区都是X轴直线上的一系列顶点,所对应的坐标Xi 保证唯一。每个景点区有个初始的热度值,而一个休息区(坐标为Xi)的热度值等于离它距离最近的景点区Xj的热度值(距离定义为|Xi-Xj|),如果此休息区与两个景点区的距离一样,则休息区的热度值选择两个景点区中的热度值最大值,如果两个热度值都一样,则随意选择其中一个。
  度度熊在出门之前会经常去查看百度地图,每次查看前会有某些景点区的热度值已发生改变,从而也会导致周围的休息区的热度值发生改变,然后度度熊想知道当前热度值<=Rk的顶点(包括景点区和休息区)有多少个
 
 
Input
  输入数据的第一行是测试Case的个数(T<=100)。
  每个Case的第一行是N(0<N<=10000),表示景点区和休息区的总数。
  接着会有N行数据,每一列首先是顶点的X坐标Xi (0< Xi <=1e8),第二列是一个整数Hi(0=<Hi <=100000),如果Hi 不为0,则表示当前顶点为风景区且初始的热度值为Hi,否则表示当前顶点为休息区。这N行数据会按照坐标Xi递增的方式依次给出。
  接着的一行数据是操作的次数K(K<=100),最后会有K行数据,每一行的第一列要么是’U’或者’Q’,’U’表示当前操作为更改热度操作,’Q’表示当前操作为查询操作。如果是更改操作,接着会有两列数据,分别是热度值要改变的风景区的下标Lk(0<=Lk<N)以及改变后的热度值Vk(0< Vk<=100000);如果是查询操作,第二列是要查询的热度范围Rk(0< Rk<=100000)
 
 
Output
  对于第k组测试数据,第一行输出Case #k:,接下来对每次查询操作(即Q操作)会输出一个整数,表示满足条件的顶点数有多少个
 
 
Sample Input
1 4 10 020 330 0 40 23Q 3 U 3 4 Q 3
 
 
Sample Output
Case #1:42
 
 
Source
2014年百度之星程序设计大赛 - 初赛(第二轮)
 
 
题目分析:
 

跟着题意模拟就行了,主要是通过对每个休息区保存离他距离最近的至多两个风景区(不可能比这个还多,因为只在X轴上),然后对每个风景区能影响到的休息区连边,当风景区的热度改变时, 就通过这条边跳到休息区,进而改变休息区的热度值(可能不会改变)。


 代码如下:


#include <stdio.h>
#include <string.h>
typedef long long ll;
const int O = 1000000;
const int maxn = 10005;
typedef struct E{
    int v, n;
}E;
typedef struct point{
    int x, h;
    int g[2];
}point;
point a[maxn];
E edge[O];
int Adj[maxn], l;
int f[maxn];
void addedge(int u, int v){
    edge[l].v = v; edge[l].n = Adj[u]; Adj[u] = l++;
}
void check(int i, int i1, int i2){
    if(!i2 || a[i1].h >= a[i2].h) a[i].h = a[i1].h;
    else if(a[i2].h > a[i1].h) a[i].h = a[i2].h;
}
int abs(int x){
    return x > 0 ? x : -x;
}
int read(){
    char ch = ' ';
    while(ch < '0' || ch > '9') ch = getchar();
    int x = 0;
    while(ch >= '0' && ch <= '9'){
        x = x * 10 + ch - '0';
        ch = getchar();
    }
    return x;
}
void work(){
    int n, q, x, y;
    char ch[2];
    n = read();
    memset(Adj, -1, sizeof(Adj[0]) * (n + 1));
    memset(a, 0, sizeof(a[0]) * (n + 1));
    l = 0;
    int flag = 0, pre = 0, next = 0;
    for(int i = 1; i <= n; ++i){
        a[i].x = read(); a[i].h = read();
        if(a[i].h) flag = 1;
    }
    if(flag){
        for(int i = 1; i <= n; ++i){
            if(!a[i].h){
                a[i].g[0] = pre;
                if(next <= i && next <= n){
                    next = i + 1;
                    while(next <= n){
                        if(a[next].h) break;
                        ++next;
                    }
                }
                a[i].g[1] = (next <= n ? next : 0);
                if(!a[i].g[0] || abs(a[i].x - a[a[i].g[0]].x) > abs(a[a[i].g[1]].x - a[i].x)){
                    a[i].g[0] = a[i].g[1];
                    a[i].g[1] = 0;
                }
                else if(abs(a[i].x - a[a[i].g[0]].x) < abs(a[a[i].g[1]].x - a[i].x)){
                    a[i].g[1] = 0;
                }
                if(a[i].g[0]) addedge(a[i].g[0], i);
                if(a[i].g[1]) addedge(a[i].g[1], i);
            }
            else pre = i;
        }
    }
    for(int i = 1; i <= n; ++i){
        if(!a[i].h) check(i, a[i].g[0], a[i].g[1]);
    }
    scanf("%d", &q);
    for(int i = 0; i < q; ++i){
        scanf("%s", ch);
        if(ch[0] == 'Q'){
            int cnt = 0;
            scanf("%d", &x);
            for(int j = 1; j <= n; ++j) if(a[j].h <= x) cnt++;
            printf("%d\n", cnt);
        }
        else{
            scanf("%d%d", &x, &y);
            a[++x].h = y;
            for(int j = Adj[x]; ~j; j = edge[j].n){
                int v = edge[j].v;
                check(v, a[v].g[0], a[v].g[1]);
            }
        }
    }
}
int main(){
    int t, cas;
    for(scanf("%d", &t), cas = 1; cas <= t; ++cas){
        printf("Case #%d:\n", cas);
        work();
    }
    return 0;
}


你可能感兴趣的:(HDU)