[BZOJ2683][BZOJ4066]简单题

试题描述

你有一个N*N的棋盘,每个格子内有一个整数,初始时的时候全部为0,现在需要维护两种操作:


命令


参数限制


内容


1 x y A


1<=x,y<=N,A是正整数


将格子x,y里的数字加上A


2 x1 y1 x2 y2


1<=x1<= x2<=N

1<=y1<= y2<=N


输出x1 y1 x2 y2这个矩形内的数字和


3



终止程序

输入

输入文件第一行一个正整数N。

接下来每行一个操作。每条命令除第一个数字之外,

均要异或上一次输出的答案last_ans,初始时last_ans=0。(BZOJ2683不需要强制在线)

输出

对于每个2操作,输出一个对应的答案。

输入示例(BZOJ2683)

4
1 2 3 3
2 1 1 3 3
1 2 2 2
2 2 2 3 4
3

输出示例(BZOJ2683)

3
5

输入示例(BZOJ4066)

4
1 2 3 3
2 1 1 3 3
1 1 1 1
2 1 1 0 7
3

输出示例(BZOJ4066)

3
5

数据规模及约定

数据规模和约定

1<=N<=500000,操作数不超过200000个,内存限制20M,保证答案在int范围内并且解码之后数据仍合法。

题解

只有权限号可以享受的双倍经验题(雾)。

2683这道数据水,最裸的kd树就卡时限过了。。。

4066这题数据强,需要加一个定期重构,就是加入的元素达到了某一些固定值就暴力把整棵kd树重新构造一遍,这样就不会被卡成“n2 的优秀算法了”。

2683(不强制在线无定期重构慢的要死):

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <cstring>
#include <string>
#include <map>
#include <set>
using namespace std;

const int BufferSize = 1 << 16;
char buffer[BufferSize], *Head, *Tail;
inline char Getchar() {
    if(Head == Tail) {
        int l = fread(buffer, 1, BufferSize, stdin);
        Tail = (Head = buffer) + l;
    }
    return *Head++;
}
int read() {
    int x = 0, f = 1; char c = Getchar();
    while(!isdigit(c)){ if(c == ‘-‘) f = -1; c = Getchar(); }
    while(isdigit(c)){ x = x * 10 + c - ‘0‘; c = Getchar(); }
    return x * f;
}

#define maxn 200010
#define oo 2147483647
int root, ToT, lc[maxn], rc[maxn];
struct Node {
	int x[2], mx[2], mn[2], val, sum;
	bool operator == (const Node& t) const { return x[0] == t.x[0] && x[1] == t.x[1]; }
} nodes[maxn];

Node x, y;
void maintain(int o) {
	int l = lc[o], r = rc[o];
	for(int i = 0; i < 2; i++) {
		nodes[o].mx[i] = max(max(nodes[l].mx[i], nodes[r].mx[i]), nodes[o].x[i]);
		nodes[o].mn[i] = min(min(nodes[l].mn[i], nodes[r].mn[i]), nodes[o].x[i]);
	}
	nodes[o].sum = nodes[l].sum + nodes[r].sum + nodes[o].val;
//	printf("maintain(%d): %d %d %d %d %d\n", o, nodes[o].sum, nodes[o].mx[0], nodes[o].mn[0], nodes[o].mx[1], nodes[o].mn[1]);
	return ;
}
void add(int& o, bool cur) {
	if(!o){ nodes[o = ++ToT] = x; return maintain(o); }
	if(nodes[o] == x){ nodes[o].val += x.val; nodes[o].sum += x.val; return maintain(o); }
	add(x.x[cur] < nodes[o].x[cur] ? lc[o] : rc[o], cur ^ 1);
	return maintain(o);
}
bool all(int o) { return x.x[0] <= nodes[o].mn[0] && nodes[o].mx[0] <= y.x[0] && x.x[1] <= nodes[o].mn[1] && nodes[o].mx[1] <= y.x[1]; }
bool has(int o) { return !(nodes[o].mx[0] < x.x[0] || nodes[o].mn[0] > y.x[0] || nodes[o].mx[1] < x.x[1] || nodes[o].mn[1] > y.x[1]); }
int query(int o) {
	if(!o) return 0;
	int ans = 0;
	if(all(lc[o])) ans += nodes[lc[o]].sum;
	else if(has(lc[o])) ans += query(lc[o]);
	if(all(rc[o])) ans += nodes[rc[o]].sum;
	else if(has(rc[o])) ans += query(rc[o]);
	int nx = nodes[o].x[0], ny = nodes[o].x[1];
	if(x.x[0] <= nx && nx <= y.x[0] && x.x[1] <= ny && ny <= y.x[1]) ans += nodes[o].val;
	return ans;
}

int main() {
	nodes[0].mx[0] = nodes[0].mx[1] = -oo;
	nodes[0].mn[0] = nodes[0].mn[1] = oo;
	nodes[0].val = nodes[0].sum = 0;
	int n = read();
	n = read();
	while(n < 3) {
		if(n == 1) {
			x.x[0] = read(); x.x[1] = read(); x.val = read();
			add(root, 1);
		}
		if(n == 2) {
			x.x[0] = read(); x.x[1] = read(); y.x[0] = read(); y.x[1] = read();
			printf("%d\n", query(root));
		}
		n = read();
	}

	return 0;
}

4066(强制在线加定期重构但还是很慢= =):

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <cstring>
#include <string>
#include <map>
#include <set>
using namespace std;

const int BufferSize = 1 << 16;
char buffer[BufferSize], *Head, *Tail;
inline char Getchar() {
    if(Head == Tail) {
        int l = fread(buffer, 1, BufferSize, stdin);
        Tail = (Head = buffer) + l;
    }
    return *Head++;
}
int read() {
    int x = 0, f = 1; char c = Getchar();
    while(!isdigit(c)){ if(c == ‘-‘) f = -1; c = Getchar(); }
    while(isdigit(c)){ x = x * 10 + c - ‘0‘; c = Getchar(); }
    return x * f;
}

#define maxn 200010
#define oo 2147483647
int root, ToT, lc[maxn], rc[maxn];
bool Cur;
struct Node {
	int x[2], mx[2], mn[2], val, sum;
	bool operator == (const Node& t) const { return x[0] == t.x[0] && x[1] == t.x[1]; }
	bool operator < (const Node& t) const { return x[Cur] < t.x[Cur]; }
} nodes[maxn];

Node x, y;
void maintain(int o) {
	int l = lc[o], r = rc[o];
	for(int i = 0; i < 2; i++) {
		nodes[o].mx[i] = max(max(nodes[l].mx[i], nodes[r].mx[i]), nodes[o].x[i]);
		nodes[o].mn[i] = min(min(nodes[l].mn[i], nodes[r].mn[i]), nodes[o].x[i]);
	}
	nodes[o].sum = nodes[l].sum + nodes[r].sum + nodes[o].val;
//	printf("maintain(%d): %d %d %d %d %d\n", o, nodes[o].sum, nodes[o].mx[0], nodes[o].mn[0], nodes[o].mx[1], nodes[o].mn[1]);
	return ;
}
void add(int& o, bool cur) {
	if(!o){ nodes[o = ++ToT] = x; return maintain(o); }
	if(nodes[o] == x){ nodes[o].val += x.val; nodes[o].sum += x.val; return maintain(o); }
	add(x.x[cur] < nodes[o].x[cur] ? lc[o] : rc[o], cur ^ 1);
	return maintain(o);
}
void build(int& o, int L, int R, int cur) {
	if(L > R){ o = 0; return ; }
	int M = L + R >> 1; o = M;
	Cur = cur; nth_element(nodes + L, nodes + M, nodes + R + 1);
	build(lc[o], L, M - 1, cur ^ 1); build(rc[o], M + 1, R, cur ^ 1);
	return maintain(o);
}
bool all(int o) { return x.x[0] <= nodes[o].mn[0] && nodes[o].mx[0] <= y.x[0] && x.x[1] <= nodes[o].mn[1] && nodes[o].mx[1] <= y.x[1]; }
bool has(int o) { return !(nodes[o].mx[0] < x.x[0] || nodes[o].mn[0] > y.x[0] || nodes[o].mx[1] < x.x[1] || nodes[o].mn[1] > y.x[1]); }
int query(int o) {
	if(!o) return 0;
	int ans = 0;
	if(all(lc[o])) ans += nodes[lc[o]].sum;
	else if(has(lc[o])) ans += query(lc[o]);
	if(all(rc[o])) ans += nodes[rc[o]].sum;
	else if(has(rc[o])) ans += query(rc[o]);
	int nx = nodes[o].x[0], ny = nodes[o].x[1];
	if(x.x[0] <= nx && nx <= y.x[0] && x.x[1] <= ny && ny <= y.x[1]) ans += nodes[o].val;
	return ans;
}

int main() {
	nodes[0].mx[0] = nodes[0].mx[1] = -oo;
	nodes[0].mn[0] = nodes[0].mn[1] = oo;
	nodes[0].val = nodes[0].sum = 0;
	int n = read(), lastans = 0;
	n = read();
	while(n < 3) {
		if(n == 1) {
			x.x[0] = read() ^ lastans; x.x[1] = read() ^ lastans; x.val = read() ^ lastans;
			add(root, 1);
			if(ToT % 1000 == 0) build(root, 1, ToT, 1);
		}
		if(n == 2) {
			x.x[0] = read() ^ lastans; x.x[1] = read() ^ lastans; y.x[0] = read() ^ lastans; y.x[1] = read() ^ lastans;
			printf("%d\n", lastans = query(root));
		}
		n = read();
	}

	return 0;
}

其实这道题我第一眼看上去是树套树删边题,结果一看内存限制20M。。。还好没写树套树= =

时间: 2024-10-28 10:34:11

[BZOJ2683][BZOJ4066]简单题的相关文章

【BZOJ2683】简单题 [分治][树状数组]

简单题 Time Limit: 50 Sec  Memory Limit: 128 MB[Submit][Status][Discuss] Description 你有一个N*N的棋盘,每个格子内有一个整数,初始时的时候全部为0,现在需要维护两种操作: 命令 参数限制 内容 1 x y A 1<=x,y<=N,A是正整数 将格子x,y里的数字加上A 2 x1 y1 x2 y2 1<=x1<= x2<=N 1<=y1<= y2<=N 输出x1 y1 x2 y2

【bzoj1176】[Balkan2007]Mokia/【bzoj2683】简单题

bzoj1176 题目描述 维护一个W*W的矩阵,初始值均为S(题目描述有误,这里的S没有任何作用!).每次操作可以增加某格子的权值,或询问某子矩阵的总权值.修改操作数M<=160000,询问数Q<=10000,W<=2000000. 输入 第一行两个整数,S,W;其中S为矩阵初始值;W为矩阵大小接下来每行为一下三种输入之一(不包含引号):1 x y a2 x1 y1 x2 y23输入1:你需要把(x,y)(第x行第y列)的格子权值增加a输入2:你需要求出以左下角为(x1,y1),右上角

【kd-tree】bzoj4066 简单题

同p1176. #include<cstdio> #include<cmath> #include<algorithm> using namespace std; #define N 200011 #define KD 2//ά¶ÈÊý int qp[2][2]; int n,root=1,m; bool dn; struct Node { int minn[KD],maxx[KD],p[KD],w,ch[2],sumv; void Init() { for(int

Bzoj4066 简单题

Time Limit: 50 Sec  Memory Limit: 20 MBSubmit: 2185  Solved: 581 Description 你有一个N*N的棋盘,每个格子内有一个整数,初始时的时候全部为0,现在需要维护两种操作: 命令 参数限制 内容 1 x y A 1<=x,y<=N,A是正整数 将格子x,y里的数字加上A 2 x1 y1 x2 y2 1<=x1<= x2<=N 1<=y1<= y2<=N 输出x1 y1 x2 y2这个矩形内

【BZOJ2683】简单题

cdq分治妙啊 (被改过题面的)原题: dydxh所出的题目是这样的:有一个N*N矩阵,给出一系列的修改和询问,修改是这样的:将(x,y)中的数字加上k,而询问是这样的:求(x1,y1)到(x2,y2)这个子矩阵内所有数字的和.虽然这么高级的数据结构题mzx这种菜逼当然不会,但是由于dydxh给mzx留了一条没有强制在线的生路,所以mzx决定挑战一下这道题. 1<=N<=500000,操作数不超过200000个,操作1中的k为正整数,且不超过2000 思路很妙,知道为什么要这样做但是感觉考场上

【BZOJ4066】简单题 KDtree

[BZOJ4066]简单题 Description 你有一个N*N的棋盘,每个格子内有一个整数,初始时的时候全部为0,现在需要维护两种操作: 命令 参数限制 内容 1 x y A 1<=x,y<=N,A是正整数 将格子x,y里的数字加上A 2 x1 y1 x2 y2 1<=x1<= x2<=N 1<=y1<= y2<=N 输出x1 y1 x2 y2这个矩形内的数字和 3 无 终止程序 Input 输入文件第一行一个正整数N. 接下来每行一个操作.每条命令除第

BZOJ2683: 简单题(CDQ分治 + 树状数组)

BZOJ2683: 简单题(CDQ分治 + 树状数组) 题意: 你有一个\(N*N\)的棋盘,每个格子内有一个整数,初始时的时候全部为\(0\),现在需要维护两种操作: 命令 参数限制 内容 \(1\ x\ y\ A\) \(1\le x,y \le N\),A是正整数 将格子\(x,y\)里的数字加上\(A\) \(2\ x1\ y1\ x2\ y2\) \(1\le x1\le x2\le N,1\le y1\le y2\le N\) 输出\(x1\ y1\ x2\ y2\)这个矩形内的数字

[bzoj4066/2683]简单题_KD-Tree

简单题 bzoj-4066 题目大意:n*n的棋盘,开始为均为0,支持:单点加权值,查询矩阵权值和,强制在线. 注释:$1\le n\le 5\cdot 10^5$,$1\le m \le 2\cdot 10^5$. 想法:KD-Tree裸题. 所谓KD-Tree,就是一个看起来贼牛逼实际上我觉着也贼牛逼的暴力... ... 算了,网上讲解一摞摞,不赘述. 这里我们只需要在KD-Tree上维护子树和即可.单点加的话往上更新呗,或者换成删除+插入也能过. 最后,附上丑陋的代码... ... #in

bzoj2683简单题

2683: 简单题 Time Limit: 50 Sec  Memory Limit: 128 MB Submit: 738  Solved: 307 [Submit][Status][Discuss] Description 你有一个N*N的棋盘,每个格子内有一个整数,初始时的时候全部为0,现在需要维护两种操作: 命令 参数限制 内容 1 x y A 1<=x,y<=N,A是正整数 将格子x,y里的数字加上A 2 x1 y1 x2 y2 1<=x1<= x2<=N 1<