Crowd
Time Limit: 5000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 2663 Accepted Submission(s): 640
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.
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.
大意就是给定一个矩阵,有两种操作,一种是更改某个点的值,一种是查询该点曼哈顿距离内的点值。
曼哈顿距离表示的是一个菱形,所以每个点旋转45°。
新点的座标表示为整数的话就是:(x-y,x+y)
为了防止x-y<0,将横座标加n即可,所以处理点就是(x-y+n,x-y)
再加上这个题数据量大,用离散化处理一下,将二维的座标映射成为一个数字,用树状数组维护更新和查询即可。
代码如下:
#include <stdio.h>
#include <iostream>
#include <stdlib.h>
#include <algorithm>
#include <string.h>
#include <math.h>
#define N 3001003
using namespace std;
int x[N],y[N];
int sym[N],val[N];
int num[N],tree[N];
int cnt;
int n,m;
int H;
int lowbit(int i)
{
return i&(-i);
}
void get(int x,int y)
{
for(int i=x;i<=H;i+=lowbit(i))
{
for(int j=y;j<=H;j+=lowbit(j))
{
num[cnt++]=i*(H+1)+j;
//这里将二维的座标映射成为一个数字,i乘的数字最小为H,当小于H时加j有可能使得两个座标投影为同一个数字
}
}
}
void add(int x,int y,int val)
{
for(int i=x;i<=H;i+=lowbit(i))
{
for(int j=y;j<=H;j+=lowbit(j))
{
int pos=lower_bound(num,num+cnt,i*(H+1)+j)-num;
tree[pos]+=val;
}
}
}
int query(int x,int y)
{
int sum=0;
for(int i=x;i>0;i-=lowbit(i))
{
for(int j=y;j>0;j-=lowbit(j))
{
int pos=lower_bound(num,num+cnt,i*(H+1)+j)-num;
if(num[pos]==i*(H+1)+j)
sum+=tree[pos];
}
}
return sum;
}
int main()
{
int newx,newy;
while(scanf("%d",&n)!=EOF&&n)
{
scanf("%d",&m);
H=n*2;//座标扩大为与来的2倍
cnt=0;
memset(tree,0,sizeof(tree));
memset(num,0,sizeof(num));
for(int i=0;i<m;i++)
{
scanf("%d%d%d%d",&sym[i],&x[i],&y[i],&val[i]);
newx=x[i]-y[i]+n;
newy=x[i]+y[i];
if(sym[i]==1)
get(newx,newy);
}
//printf("%d\n",cnt);
sort(num,num+cnt);
cnt=unique(num,num+cnt)-num;
//unique将重复的元素去掉,加在数组的最后
for(int i=0;i<m;i++)
{
newx=x[i]-y[i]+n;
newy=x[i]+y[i];
if(sym[i]==1)
add(newx,newy,val[i]);
else
{
int x1=max(1,newx-val[i]);//防止越界
int x2=min(H,newx+val[i]);
int y1=max(1,newy-val[i]);
int y2=min(H,newy+val[i]);
printf("%d\n",query(x2,y2)-query(x1-1,y2)-query(x2,y1-1)+query(x1-1,y1-1));
}
}
}
return 0;
}