HDOJ 4456 Crowd 离散化+二维树状数组

将坐标旋转45度就可以得到正方形,可以用二维树状数组求解...

为了节省内存,提前将树状数组中会被更新的点全都存下来,并离散化

Crowd

Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)

Total Submission(s): 1199    Accepted Submission(s): 282

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

2012 Asia Hangzhou Regional Contest

/* ***********************************************
Author        :CKboss
Created Time  :2015年08月31日 星期一 10时17分01秒
File Name     :HDOJ4456.cpp
************************************************ */

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
#include <cmath>
#include <cstdlib>
#include <vector>
#include <queue>
#include <set>
#include <map>

using namespace std;

const int maxn=88888;
const int maxm=4004000;

int tree[maxm];
int hs[maxm],hn;
int n,m;
int w;
int p[maxn],x[maxn],y[maxn],d[maxn];

inline int lowbit(int x) { return x&(-x); }

void ready(int x,int y)
{
	for(int i=x;i<=w;i+=lowbit(i))
	{
		for(int j=y;j<=w;j+=lowbit(j))
		{
			hs[hn++]=i*w+j;
		}
	}
}

void Add(int x,int y,int v)
{
	for(int i=x;i<=w;i+=lowbit(i))
	{
		for(int j=y;j<=w;j+=lowbit(j))
		{
			int id=lower_bound(hs,hs+hn,i*w+j)-hs;
			tree[id]+=v;
		}
	}
}

int Sum(int x,int y)
{
	x=max(x,0); x=min(x,w);
	y=max(y,0); y=min(y,w);

	int ret=0;
	for(int i=x;i>0;i-=lowbit(i))
	{
		for(int j=y;j>0;j-=lowbit(j))
		{
			int id=lower_bound(hs,hs+hn,i*w+j)-hs;
			if(hs[id]==i*w+j) ret+=tree[id];
		}
	}
	return ret;
}

int main()
{
	//freopen("in.txt","r",stdin);
	//freopen("out.txt","w",stdout);

	while(scanf("%d",&n)!=EOF&&n)
	{
		scanf("%d",&m);
		w=2*n; hn=0;
		memset(tree,0,sizeof(tree));

		for(int i=0;i<m;i++)
		{
			scanf("%d%d%d%d",p+i,x+i,y+i,d+i);
			if(p[i]==1)
			{
				int nx=x[i]+y[i];
				int ny=y[i]-x[i]+n;
				ready(nx,ny);
			}
		}

		sort(hs,hs+hn);
		hn=unique(hs,hs+hn)-hs;

		for(int i=0;i<m;i++)
		{
			int nx=x[i]+y[i];
			int ny=y[i]-x[i]+n;
			if(p[i]==1)
			{
				Add(nx,ny,d[i]);
			}
			else if(p[i]==2)
			{
				int x1,y1,x2,y2,x3,y3,x4,y4;

				/// X=x+y  Y=y-x+n;
				x1=nx+d[i]; y1=ny+d[i];
				x2=nx-d[i]; y2=ny+d[i]; x2--;
				x3=nx+d[i]; y3=ny-d[i]; y3--;
				x4=nx-d[i]; y4=ny-d[i]; x4--; y4--;

				printf("%d\n",Sum(x1,y1)-Sum(x2,y2)-Sum(x3,y3)+Sum(x4,y4));
			}
		}
	}

    return 0;
}

版权声明:来自: 码代码的猿猿的AC之路 http://blog.csdn.net/ck_boss

时间: 2024-10-18 21:24:21

HDOJ 4456 Crowd 离散化+二维树状数组的相关文章

HDU_4456_二维树状数组

http://acm.hdu.edu.cn/showproblem.php?pid=4456 第一道二维树状数组就这么麻烦,题目要计算的是一个菱形范围内的和,于是可以把原来的坐标系旋转45度,就是求一个正方形范围内的和,这里还涉及到坐标系平移和放大,由于题目数据较大,用了离散化来保存需要处理的点,放在h数组内,对应的二维树状数组存在tree数组内. #include<iostream> #include<cstring> #include<cstdio> #includ

bzoj3262: 陌上花开 二维树状数组

众所周知三维偏序可以树套树或者cdq 然后我就写了二维离散化+二维树状数组 然后被cdq艹飞了(ToT) #include<cstdio> #include<algorithm> #define N 100005 #define J i+(i&-i) #define F lower_bound #define G upper_bound using namespace std; struct io_t{ operator int(){ int x; scanf("

hdu 4456 Crowd(二维树状数组)

题目链接:hdu 4456 Crowd 题目大意:给定N,然后M次操作 1 x y z:在x,y的位置加z 2 x y z:询问与x,y曼哈顿距离小于z的点值和. 解题思路:将矩阵旋转45度,然后询问就等于是询问一个矩形,可以用容斥定理搞,维护用二维树状数组,但是空间开 不下,直接用离散化,将有用到的点处理出来. #include <cstdio> #include <cstring> #include <algorithm> using namespace std;

hdoj 1892(二维树状数组)

Problem H Time Limit : 5000/3000ms (Java/Other)   Memory Limit : 65535/32768K (Java/Other) Total Submission(s) : 8   Accepted Submission(s) : 3 Font: Times New Roman | Verdana | Georgia Font Size: ← → Problem Description Now I am leaving hust acm. In

hdu4456 Crowd(二维树状数组)

题意:给出一个n*n的矩阵,然后m个operation,1表示坐标(x,y)的值加z,2表示与坐标(x,y)的曼哈顿距离不超过z的点的权值和. 解题思路:将矩阵侧过来45度,发现询问的时候,有效的点构成的其实是一个矩阵.然后就变成了单点修改,求矩阵和的问题.我们考虑裸二维树状数组的做法,会发现矩阵太大,但是注意到,初始的时候,矩阵里面所有的值都为0,那么这个二维树状数组中,有效的点就是修改的那些点,以及掌控这些点的区间.这里总的状态数只有m*logn*logn,所以我们把operation都拿出

USACO5.3 IDDFS_强连通_二维树状数组_斐蜀定理_矩形切割

启发式搜索 启发式搜索的主要思想是通过评价一个状态有"多好"来改进对于解的搜索. 方法#1:启发式剪枝 估价函数最简单最普通的用法是进行剪枝.假设有一个求最小代价的一个搜索,使用一个可行的估价函数.如果搜到当前状态时代价为A,这个状态的估价函数是B,那么从这个状态开始搜所能得到的最小代价是A+B.如果当前最优解是C满足C 方法#2:最佳优先搜索 最佳搜索可以看成贪心的深度优先搜索. 与一般搜索随意扩展后继节点不同,最优优先搜索按照估价函数所给的他们的"好坏"的顺序扩

【二维树状数组】【CF10D】 LCIS

传送门 Description 给你两个串,求他们的最长公共上升子序列 Input 第一行是第一个串的长度\(n\) 第二行\(n\)个数代表第一个串 第三行是第二个串的长度\(m\) 第四行\(m\)个数代表第二个串 Output 输出最长子序列的长度以及方案 Hint \(For~All:\) \(0~\leq~n~\leq~500\) Solutoin 先考虑朴素DP,可以设\(f_{i,j}\)代表第一个串选前\(i\)个,第二个串选前\(j\)个的答案,转移显然\(f_{i,j}=\m

【二维树状数组】See you~

https://www.bnuoj.com/v3/contest_show.php?cid=9148#problem/F [题意] 给定一个矩阵,每个格子的初始值为1.现在可以对矩阵有四种操作: A x y n1 :给格点(x,y)的值加n1 D x y n1: 给格点(x,y)的值减n1,如果现在格点的值不够n1,把格点置0 M x1 y1 x2 y2:(x1,y1)移动给(x2,y2)n1个 S x1 y1 x2 y2 查询子矩阵的和 [思路] 当然是二维树状数组 但是一定要注意:lowbi

POJ 1195 Mobile phones(二维树状数组)

题目链接:POJ 1195 题意: 给出一个S*S的矩阵(行.列号从1开始),每个元素初始值为0,有两种操作:一种是第X行第Y列元素值加A:另一种是查询给定范围矩阵的所有元素之和(L<=X<=R,B<=Y<=T). 分析: 查询给定范围矩阵的所有元素之和是二维区间和,可以转换为二维前缀和求值.类比一维前缀和求法,二维区间和S(L, B, R, T) = S(1, 1, R, T) - S(1 ,1, L-1, T) - S(1, 1, R, B-1) + S(1, 1, L-1,