Population zoj 3018

Population zoj 3018

题目链接

Population
Time Limit: 10000 msMemory Limit: 32768 KB
It is always exciting to see people settling in a new continent. As the head of the population management office, you are supposed to know, at any time, how people are distributed in this continent.

The continent is divided into square regions, each has a center with integer coordinates (x, y). Hence all the people coming into that region are considered to be settled at the center position. Given the positions of the corners of a rectangle region, you are supposed to count the number of people living in that region.

Input

Your program must read inputs from the standard input. Since there are up to 32768 different regions and possibly even more queries, please use "scanf" and "printf" instead of "cin" and "cout" to avoid timeout.

The character "I" in a line signals the coming in of new groups of people. In the following lines, each line contains three integers: X, Y, and N, where X and Y (1 <= X, Y <= 20000) are the coordinates of the region's center, and N (1 <= N <= 10000) is the number of people coming in.

The character "Q" in a line signals the query of population. The following lines each contains four numbers: Xmin, Xmax, Ymin, Ymax, where (Xmin, Ymin) and (Xmax, Ymax) are the integer coordinates of the lower left corner and the upper right corner of the rectangle, respectively.

The character "E" signals the end of a test case. Process to the end of file.

Output

For each "Q" case, print to the standard output in a line the population in the given rectangle region. That is, you are supposed to count the number of people living at all the positions (x, y) such that Xmin <= x <= Xmax, and Ymin <= y <= Ymax.

Sample Input

I
8 20 1
4 5 1
10 11 1
12 10 1
18 14 1
Q
8 10 5 15
8 20 10 14
I
7 6 1
10 3 2
7 2 1
2 3 2
10 3 1
Q
2 20 2 20
E
Sample Output

1
3
12

[思路]:求的是一个二维区间之间的和
朴素想法,使用一个二维数组来维护二维前缀和,但是通过观察数据范围发现空间开不下
那么我们可以联想到数据结构,如果是一维的维护,可以使用线段树来维护
我们也可以联想到线段树
那么引出一个概念二维线段树,即针对x轴,y轴取两个中点,xmid,ymid
那么对应的子区间,即为4块,即中点划分后的左上,左下,右上,右下
这样就实现了区间的划分,即一个线段树节点不止有l,r;
有的应该是<lx, ly> <rx, ry>,左下点跟右上点,
因为这个题目的范围很大,2e5*2e5,所以直接建树空间也是放不下的。
但是给的点数不多,那么我们可以动态建树
思路类似于使用数组模拟链表
模拟就完事了
注意这里有个非常恶心的坑点,输入E后,还没有结束,是多组输入
附上代码:
#include <bits/stdc++.h>
using namespace std;
/**
 * 面积树
 * 四叉树
 * **/
typedef long long LL;
int str_to_int(string a){
    int sum = 0;
    for(int i = 0; i < a.length(); i ++){
        sum = sum * 10 + (a[i] - '0');
    }
    return sum;
}
int tot = 0;
const int MAXN = 1e7 + 5;
struct AREA_tree{
    struct NODE{
        int lx, ly, rx, ry;///左下角 右上角
        LL sum;///区间的总和
        int son[4];///儿子节点对应的是点在数组中的编号
        /*划分为四个部分,四个儿子节点对应四个部分
        0 <xmid + 1, ymid + 1> <rx, ry>
        1 <lx, ymid + 1> <xmid, ry>
        2 <lx, ly> <xmid, ymid>
        3 <xmid + 1, ly> <rx, ymid>
        */
    }tree[MAXN];
    void Init_NODE(NODE &x){
        for(int i = 0; i < 4; i ++){
            x.son[i] = -1;
        }///清空儿子节点,代表没有下一个区间
    }
    void Init(){
        tot = 0;///初始化为0
    }
    int add(int lx, int ly, int rx, int ry){///添加一个<lx, ly> <rx, ry>的节点
        tree[tot].lx = lx, tree[tot].rx = rx, tree[tot].ly = ly, tree[tot].ry = ry;
        Init_NODE(tree[tot]);
        tree[tot].sum = 0;
        return tot ++;
    }
    void update(int root, int x, int y, int value){///更新一个节点
        if(tree[root].lx == tree[root].rx && tree[root].ly == tree[root].ry){
            tree[root].sum += value;///如果跑到单点上,那么更新总和
            return ;
        }
        int xmid = (tree[root].lx + tree[root].rx) >> 1;///xmid
        int ymid = (tree[root].ly + tree[root].ry) >> 1;///ymid
        /*
        0 <xmid + 1, ymid + 1> <rx, ry>
        1 <lx, ymid + 1> <xmid, ry>
        2 <lx, ly> <xmid, ymid>
        3 <xmid + 1, ly> <rx, ymid>
        */
       int rx, ry, lx, ly;
       rx = tree[root].rx, ry = tree[root].ry, lx = tree[root].lx, ly = tree[root].ly;
        ///判断更新的区间在哪个子区间
        if(x <= rx && y <= ry && x >= xmid + 1 && y >= ymid + 1){
            if(tree[root].son[0] == -1){///右上
                tree[root].son[0] = add(xmid + 1, ymid + 1, rx, ry);
            }
            update(tree[root].son[0], x, y, value);
        }
        else if(x <= xmid && y <= ry && x >= lx && y >= ymid + 1){///左上
            if(tree[root].son[1] == -1){
                tree[root].son[1] = add(lx, ymid + 1, xmid, ry);
            }
            update(tree[root].son[1], x, y, value);
        }
        else if(x <= xmid && y <= ymid && x >= lx && y >= ly){///左下
            if(tree[root].son[2] == -1){
                tree[root].son[2] = add(lx, ly, xmid, ymid);
            }
            update(tree[root].son[2], x, y, value);
        }
        else if(x <= rx && y <= ymid && x >= xmid + 1 && y >= ly){///右下
            if(tree[root].son[3] == -1){
                tree[root].son[3] = add(xmid + 1, ly, rx, ymid);
            }
            update(tree[root].son[3], x, y, value);
        }
        int sum = 0;
        for(int i = 0; i < 4; i ++){
            if(tree[root].son[i] != -1){
                sum += tree[tree[root].son[i]].sum;
            }
        }///更新相当于线段树的push_up
        tree[root].sum = sum;
        return ;
    }
    LL query(int root, int xmin, int ymin, int xmax, int ymax){
        if(tree[root].lx >= xmin && tree[root].ly >= ymin && tree[root].rx <= xmax && tree[root].ry <= ymax){
            return tree[root].sum;
        }
        int xmid = (tree[root].lx + tree[root].rx) >> 1;
        int ymid = (tree[root].ly + tree[root].ry) >> 1;
        /*
        0 <xmid + 1, ymid + 1> <rx, ry>
        1 <lx, ymid + 1> <xmid, ry>
        2 <lx, ly> <xmid, ymid>
        3 <xmid + 1, ly> <rx, ymid>
        查询语句,依旧是查询四个区间
        判断是否应该查询这个区间
        或者时对应的区间被包含
        */
        int rx, ry, lx, ly;
        rx = tree[root].rx, ry = tree[root].ry, lx = tree[root].lx, ly = tree[root].ly;
        LL re = 0;
        if(xmin <= xmid && ymin <= ymid){
            if(tree[root].son[2] != -1)
            re += query(tree[root].son[2], xmin, ymin, xmax, ymax);
        }
        if(xmax > xmid && ymin <= ymid){
            if(tree[root].son[3] != -1)
            re += query(tree[root].son[3], xmin, ymin, xmax, ymax);
        }
        if(xmin <= xmid && ymax > ymid){
            if(tree[root].son[1] != -1)
            re += query(tree[root].son[1], xmin, ymin, xmax, ymax);
        }
        if(xmax > xmid && ymax > ymid){
            if(tree[root].son[0] != -1)
            re += query(tree[root].son[0], xmin, ymin, xmax, ymax);
        }
        return re;
    }
}area_tree;
int main(){
    #ifdef moxin
    freopen("C:\\Users\\user\\Desktop\\dp_data\\1.in", "r", stdin);
    freopen("C:\\Users\\user\\Desktop\\dp_data\\1.out", "w", stdout);
    #endif
    ios::sync_with_stdio(false);
    string str;
    int flag = 0;///0 - I 1 - Q
    area_tree.Init();
    area_tree.add(1, 1, 20005, 20005);
    while(cin >> str){
        if(str[0] == 'E'){
            area_tree.Init();
            area_tree.add(1, 1, 20005, 20005); 
            continue;
        } 
        if(str[0] == 'I') {
            flag = 0; continue;
        }
        if(str[0] == 'Q') {
            flag = 1; continue;
        }
        if(flag == 0){
            int x = str_to_int(str);
            int y, z;
            cin >> y >> z;
            area_tree.update(0, x, y, z);
        }
        else if(flag == 1){
            int x1, y1, x2, y2;
            x1 = str_to_int(str);
            cin >> x2 >> y1 >> y2;
            cout << area_tree.query(0, x1, y1, x2, y2) << endl;
        }
    }
    return 0;
}

转载于:https://www.cnblogs.com/qq136155330/p/11539776.html

已标记关键词 清除标记
表情包
插入表情
评论将由博主筛选后显示,对所有人可见 | 还能输入1000个字符
相关推荐
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页