HDU4456-Crowd

本文介绍了一种利用二维树状数组结合离散化技术解决城市街道拥堵度计算问题的方法。通过坐标旋转和离散化处理,有效解决了大规模数据下的计算难题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Crowd

                                                                    Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
                                                                                            Total Submission(s): 2594    Accepted Submission(s): 612


Problem Description
City F in the southern China is preparing lanterns festival celebration along the streets to celebrate the festival. 
Since frequent accidents had happened last year when the citizens went out to admire the colorful lanterns, City F is planning to develop a system to calculate the degree of congestion of the intersection of two streets. 
The map of City F is organized in an N×N grid (N north-south streets and N west-east street). For each intersection of streets, we define a density value for the crowd on the intersection. 
Initially, the density value of every intersection is zero. As time goes by, the density values may change frequently. A set of cameras with new graphical recognition technology can calculate the density value of the intersection easily in a short time.
But the administrator of the police office is planning to develop a system to calculate the degree of congestion. For some consideration, they come up with a conception called "k-dimension congestion degree". The "k-dimension congestion degree" of intersection (x0,y0) is represented as "c(x0,y0,k)", and it can be calculated by the formula below:

Here, d(x,y) stands for the density value on intersection (x,y) and (x,y) must be in the N×N grid. The formula means that all the intersections in the range of manhattan distance k from (x0,y0) effect the k-dimension congestion degree of (x0,y0) equally, so we just simply sum them up to get the k-dimension congestion degree of (x0,y0). 
The figure below shows a 7×7 grid, and it shows that if you want to get the 2-dimension congestion degree of intersection (4,2),you should sum up the density values of all marked intersections.

 

Input
These are multiple test cases. 
Each test case begins with a line with two integers N, M, meaning that the city is an N×N grid and there will be M queries or events as time goes by. (1 ≤ N ≤10 000, 1 ≤ M ≤ 80 000) Then M lines follow. Each line indicates a query or an event which is given in form of (p, x, y, z), here p = 1 or 2, 1 ≤ x ≤ N, 1 ≤ y ≤ N. 
The meaning of different p is shown below.
1. p = 1 the value of d(x,y) is increased by z, here -100 ≤ z ≤ 100.
2. p = 2 query the value of c(x,y,z), here 0 ≤ z ≤ 2N-1.
Input is terminated by N=0.
 

Output
For each query, output the value for c(x,y,z) in a line.
 

Sample Input
  
8 5 1 8 8 1 1 1 1 -2 2 5 5 6 1 5 5 3 2 2 3 9 3 2 1 3 2 -9 2 3 2 0 0
 

Sample Output
  
1 1 -9
 

Source
 

Recommend
 

题意:给定一个n*n的网格,有两种操作,一种是改变网格上的某个单点的权值,另一种是求到一点曼哈顿距离为小于等于k的所有的权值和,初始化网格所有点的权值为0。

解题思路:题目中主要要解决的两个问题是:如何将题目中的曼哈顿距离转化为规则的矩形,以及如何避免开辟一个巨大的数组。解决这两个问题后就是一个简单的二维树状数组了

转化为矩形:把所有的点都旋转45度,需要一个2n*2n的数组数组才能容下坐标转换之后的图,坐标的转化方式为xx=x-y+n,yy=x+y。可以这样看,转化之后的同行相邻两列的坐标差为(-1, 1), 相邻两列相邻两行的坐标差为(1, 1)。如果以(0, 0)为参考点(即该点转化前后位置不发生变化),那么(x, y)就变为(x-y, x+y),因为所有的点都应该在这个2n*2n的矩形中,因此我们给(1,1)这个点衡坐标加上n,纵坐标也可以-1,这样就能让最靠左边的点的列从1开始,这样转化后(1,1)->(n,2),(1,n)->(1,n+1),(n,1)->(2n-1,n+1),(n,n)->(n, 2n)。

避免开一个大的数组:转化之后的数组达到了20000*20000,所以需要进行离散化,离散化后就可以存的下了



#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <algorithm>
#include <queue>
#include <vector>
#include <set>
#include <stack>
#include <map>
#include <climits>

using namespace std;

#define LL long long
const int INF = 0x3f3f3f3f;

int n,m,w;
int h[5000009],cnt,a[5000009];
int p[80009],x[80009],y[80009],z[80009];

int lowbit(int k)
{
    return k&-k;
}

void f(int x,int y)
{
    for (int i=x;i<=w;i+=lowbit(i))
        for (int j=y;j <=w;j+=lowbit(j))
            h[cnt++]=i*w+j;
}

void add(int x,int y,int val)
{
    for(int i = x; i <= w; i += lowbit(i))
        for(int j = y; j <= w; j += lowbit(j))
        {
            int k=lower_bound(h,h+cnt,i*w+j)-h;
            a[k]+=val;
        }
}

int getsum(int x,int y)
{
    int sum=0;
    for(int i=x;i;i-=lowbit(i))
        for(int j=y;j;j-=lowbit(j))
        {
            int k=lower_bound(h,h+cnt,i*w+j)-h;
            if(h[k]==i*w+j) sum+=a[k];
        }
    return sum;
}

int main()
{
    while(~scanf("%d",&n)&&n)
    {
        scanf("%d", &m);
        w=n*2;
        cnt=0;
        memset(a, 0, sizeof a);
        for (int i=0;i<m;i++)
        {
            scanf("%d%d%d%d",&p[i],&x[i],&y[i],&z[i]);
            int xx=x[i]-y[i]+n;
            int yy=x[i]+y[i];
            if(p[i]==1) f(xx,yy);
        }
        sort(h,h+cnt);
        cnt=unique(h,h+cnt)-h;
        for(int i=0;i<m;i++)
        {
            int xx=x[i]-y[i]+n;
            int yy=x[i]+y[i];
            if(p[i]==1) add(xx,yy,z[i]);
            else
            {
                int x1 = max(1, xx-z[i]);
                int y1 = max(1, yy-z[i]);
                int x2 = min(w, xx+z[i]);
                int y2 = min(w, yy+z[i]);
                printf("%d\n", getsum(x2, y2) - getsum(x1 - 1, y2) - getsum(x2, y1 - 1) + getsum(x1 - 1, y1 - 1));
            }
        }
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值