【Foreign】画方框 [主席树]
画方框
Time Limit: 10 Sec Memory Limit: 256 MB
Description

Input

Output
输出一行一个整数,表示 CD 最多可能画了几个方框。
Sample Input
3
1 1 1
1 0 1
1 1 1
Sample Output
9
HINT

Main idea
给定一个01矩阵,1表示有标记,询问正方形方框的个数。
Solution
首先,我们先从 维护对角线上的点 这一层面来考虑。
我们先把一个点 能向左向上拓展的最大长度 以及 能向右向下的最长长度 预处理出来。
那么这时候,我们考虑 对于一条对角线上的点 怎么 在O(nlogn)以内 统计出答案。必然要用到某些数据结构。
举个例子,比如这个数据:
1 1 1 1
1 0 0 0
1 0 0 1
1 0 1 1
我们现在统计中间对角线的答案。
现在查询第一个点(1,1),他向右向下拓展长度为 4 。
就是查询,后面三个点中 可以向左上拓展的长度 (2,2)>=1 (3,3)>=2 (4,4)>=3,
这三个条件满足了几个。
这样的话,我们发现:每次统计一个点的时候 查询的就是:在这个点 可以向右向下拓展 到的范围内,它后面的第 i 个点 可以向左向上拓展长度 是否 > i。
我们发现:查询后面若干个数的值是否 > 一个等差数列比较复杂。
于是乎,若统计第id个的答案,后面第num个点(在向右向下范围内)可以被统计所需要满足的条件是:num - id + 1 <= val 也就是 num - val + 1 <= id。(其中val表示 这个点可以向左向上拓展的长度)
所以我们如果把 i - val + 1 加入到一个数据结构中的话,
查询的就是:某一范围内 <=一个定值 的数的个数。
那直接用主席树来做就好了。
这样我们就解决了这个问题 QWQ。
Code
#include<iostream>
#include<string>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<queue>
using namespace std;
typedef long long s64; const int ONE = ;
const int INF = ; int n;
int a[ONE][ONE];
int Ans; struct power
{
int left, right;
int up, down;
int L, R;
}A[ONE][ONE]; int cnt, res;
struct point
{
int root;
int value;
int left, right;
}Node[ONE * ]; int get()
{
int res=,Q=;char c;
while( (c=getchar())< || c> )
if(c=='-')Q=-;
res=c-;
while( (c=getchar())>= && c<= )
res=res*+c-;
return res*Q;
} void Deal_first()
{
for(int i = ; i <= n; i++)
{
for(int j = n; j >= ; j--)
if(a[i][j]) A[i][j].right = A[i][j + ].right + ;
else A[i][j].right = ;
for(int j = ; j <= n; j++)
if(a[i][j]) A[i][j].left = A[i][j - ].left + ;
else A[i][j].left = ;
} for(int j = ; j <= n; j++)
{
for(int i = n; i >= ; i--)
if(a[i][j]) A[i][j].down = A[i + ][j].down + ;
else A[i][j].down = ;
for(int i = ; i <= n; i++)
if(a[i][j]) A[i][j].up = A[i - ][j].up + ;
else A[i][j].up = ;
} for(int i = ; i <= n; i++)
for(int j = ; j <= n; j++)
A[i][j].L = min(A[i][j].left, A[i][j].up),
A[i][j].R = min(A[i][j].right, A[i][j].down);
} void Update(int &x, int y, int L, int R, int Q, int val)
{
x = ++cnt;
Node[x].left = Node[y].left;
Node[x].right = Node[y].right;
Node[x].value = Node[y].value + val;
if(L == R) return; int M = L + R >> ;
if(Q <= M)
Update(Node[x].left, Node[y].left, L, M, Q, val);
else
Update(Node[x].right, Node[y].right, M + , R, Q, val);
} void Query(int x, int y, int l, int r, int L, int R)
{
if(L <= l && r <= R)
{
res += Node[y].value - Node[x].value;
return;
} int mid = l + r >> ; if(L <= mid) Query(Node[x].left, Node[y].left, l, mid, L, R);
if(mid + <=R) Query(Node[x].right, Node[y].right, mid + , r, L, R);
} int main()
{
n = get();
for(int i = ; i <= n; i++)
for(int j = ; j <= n; j++)
a[i][j] = get(); Deal_first(); for(int id = ; id <= n; id++)
{
for(int x = id, y = ; x <= n; x++, y++)
Update(Node[y].root, Node[y - ].root, , INF, y - A[x][y].L + , ); for(int x = id, y = ; x <= n; x++, y++)
{
res = ;
if(A[x][y].R)
Query(Node[y - ].root, Node[y + A[x][y].R - ].root, , INF, , y);
Ans += res;
} cnt = ;
for(int i = ; i <= cnt; i++)
Node[i].left = Node[i].right = Node[i].root = Node[i].value = ;
} for(int id = ; id <= n; id++)
{
for(int y = id, x = ; y <= n; y++, x++)
Update(Node[x].root, Node[x - ].root, , INF, x - A[x][y].L + , ); for(int y = id, x = ; y <= n; y++, x++)
{
res = ;
if(A[x][y].R)
Query(Node[x - ].root, Node[x + A[x][y].R - ].root, , INF, , x);
Ans += res;
} cnt = ;
for(int i = ; i <= cnt; i++)
Node[i].left = Node[i].right = Node[i].root = Node[i].value = ;
} printf("%d", Ans);
}
【Foreign】画方框 [主席树]的更多相关文章
- 主席树入门(区间第k大)
主席树入门 时隔5个月,我又来填主席树的坑了,现在才发现学算法真的要懂了之后,再自己调试,慢慢写出来,如果不懂,就只会按照代码敲,是不会有任何提升的,都不如不照着敲. 所以搞算法一定要弄清原理,和代码 ...
- 【BZOJ】1146: [CTSC2008]网络管理Network(树链剖分+线段树套平衡树+二分 / dfs序+树状数组+主席树)
http://www.lydsy.com/JudgeOnline/problem.php?id=1146 第一种做法(时间太感人): 第二种做法(rank5,好开心) ================ ...
- BZOJ 4539: [Hnoi2016]树 [主席树 lca]
4539: [Hnoi2016]树 题意:不想写.复制模板树的子树,查询两点间距离. *** 终于有一道会做的题了...... 画一画发现可以把每次复制的子树看成一个大点来建一棵树,两点的lca一定在 ...
- bzoj 4448 [Scoi2015]情报传递 (树链剖分+主席树)
题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=4448 题面: Description 奈特公司是一个巨大的情报公司,它有着庞大的情报网络 ...
- 线段树简单入门 (含普通线段树, zkw线段树, 主席树)
线段树简单入门 递归版线段树 线段树的定义 线段树, 顾名思义, 就是每个节点表示一个区间. 线段树通常维护一些区间的值, 例如区间和. 比如, 上图 \([2, 5]\) 区间的和, 为以下区间的和 ...
- 五月月赛 寻宝 exkmp + 主席树
: 寻宝 时间限制: Sec 内存限制: MB 提交: 解决: [提交] [状态] [讨论版] [命题人:admin] 题目描述 采蘑菇的小西佬找到了一张上古年间的藏宝图,上面画着m座连绵不断的山,他 ...
- 【学术篇】CF833B TheBakery 分治dp+主席树
题目の传送门~ 题目大意: 将\(n\)个蛋糕分成恰好\(k\)份, 求每份中包含的蛋糕的种类数之和的最大值. 这题有两种做法. 第一种是线段树优化dp, 我还没有考虑. 另一种就是分治+主席树. 然 ...
- 权值线段树&&可持久化线段树&&主席树
权值线段树 顾名思义,就是以权值为下标建立的线段树. 现在让我们来考虑考虑上面那句话的产生的三个小问题: 1. 如果说权值作为下标了,那这颗线段树里存什么呢? ----- 这颗线段树中, 记录每个值出 ...
- bzoj3207--Hash+主席树
题目大意: 给定一个n个数的序列和m个询问(n,m<=100000)和k,每个询问包含k+2个数字:l,r,b[1],b[2]...b[k],要求输出b[1]~b[k]在[l,r]中是否出现. ...
随机推荐
- qwe
这次作业我负责的部分是把爬取完的聊天记录经行数据挖掘以及经行各种普通过滤高级过滤等. 运行截图如下: 数据分为四部分:账户名.qq/邮箱.包含关键词的发言次数.包含关键词的发言字数. 遇到的困难及解决 ...
- .net下将exe改造为既能双击独立运行又能注册为windows服务
最近项目中需要将一些业务的处理程序改造为windows服务,但是考虑到实际需求,也需要能够直接双击运行这些处理程序.首先第一步想到的就是原来的项目不变,只需要在加一个windows服务的项目就行.但是 ...
- python获取指定长度的字符串
from random import Random def random_str(randomlength=31): str = '' chars = 'abcdefghijklmnopqrstuvw ...
- 结对作业二——WordCount进阶版
软工作业三 要求地址 作业要求地址 结对码云项目地址 结对伙伴:秦玉 博客地址 PSP表格 PSP2.1 个人开发流程 预估耗费时间(分钟) 实际耗费时间(分钟) Planning 计划 10 7 · ...
- mybatis小结-001
代码不能直接copy运行,有些内容是为了说明知识点 1,sqlMqpConfig.xml <?xml version="1.0" encoding="UTF-8&q ...
- DELPHI Showmodal 模式窗体
Showmodal 是个函数, Show 是个过程 1. Showmodal: 概念 : 当你调用一个窗口用 SHOWMODAL 时 , 当这个窗口显示出来后 , 程序不会继续自己执行 , 而 ...
- placeholder 颜色
/* placeholder颜色 */::-webkit-input-placeholder { /* WebKit browsers */color: #ccc;}:-moz-placeholder ...
- c/c++中的关键字(static、const、inline、friend)
static:1.a.c语言中static修饰的局部变量在编译时赋初始值,只赋初始值一次,在函数运行时已有初值,每次调用函数时不用重新赋值,指示保留上次 函 数调用结束时的值. 如果定义局部变量不赋初 ...
- Codeforces 1025D(区间dp)
容易想到设f[i][j][k]为i~j区间以k为根是否能构成bst.这样是O(n4)的.考虑将状态改为f[i][j][0/1]表示i~j区间以i-1/j+1为根能否构成bst.显然如果是i-1作为根的 ...
- eval以及时间操作
1. 在Python里面 val=eval(“1+1”) 只能执行简单的表达式,不能执行有逻辑性的代码.并且能拿到返回值.可以执行字符串的计算: exec() 执行代码: 在JS里面:eval可以实 ...