【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]中是否出现. ...
随机推荐
- 20145214 《Java程序设计》第4周学习总结
20145214 <Java程序设计>第4周学习总结 教材学习内容总结 继承 继承基本上就是避免多个类间重复定义共同行为.要避免在程序设计上出现重复,可以把相同的程序代码提升为父类. 关键 ...
- Alpha-2
前言 失心疯病源2 团队代码管理github 站立会议 队名:PMS 530雨勤(组长) 今天完成了那些任务 17:30~21:30 又测试了一些算法和代码,时间不能再拖下去了,要尽快进入代码阶段,决 ...
- 团队作业7——第二次项目冲刺(Beta版本)
团队作业7——第二次项目冲刺-Beta版本项目计划 团队作业7——第二次项目冲刺(Beta版本)-第一篇 团队作业7——第二次项目冲刺(Beta版本)-第二篇 团队作业7——第二次项目冲刺(Beta版 ...
- iOS开发应用程序生命周期
各个程序运行状态时代理的回调: - (BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(NSD ...
- 把jar包加入本地maven库内
1首先,在项目的pom.xml文件中加入 <dependency><groupId>taobao-alidayu</groupId> //名字随便取不要跟已有的重 ...
- KindEditor是一套很方便的html编译器插件
KindEditor是一套很方便的html编译器插件.在这里做一个简单的使用介绍. 首先在官网上下载最新的KindEditor文件(里面有jsp,asp等不同版本文件夹,可以删掉你不需要的版本), 把 ...
- memcached安装与启动
windows 安装1.4.4版本 https://pan.baidu.com/s/1xX1NThLqeq2zNMaqONFgkQ 解压,“以管理员身份” 运行cmd,切换到memcached根目录, ...
- GSL介绍【转】
GSL(GNU Scientific Library)是一个C写成的用于科学计算的库,下面是一些相关的包 http://www.thebigdata.cn/JiShuBoKe/5612.html
- P1349 广义斐波那契数列
题目描述 广义的斐波那契数列是指形如an=p*an-1+q*an-2的数列.今给定数列的两系数p和q,以及数列的最前两项a1和a2,另给出两个整数n和m,试求数列的第n项an除以m的余数. 输入输出格 ...
- P1315 观光公交
题目描述 风景迷人的小城Y 市,拥有n 个美丽的景点.由于慕名而来的游客越来越多,Y 市特意安排了一辆观光公交车,为游客提供更便捷的交通服务.观光公交车在第 0 分钟出现在 1号景点,随后依次前往 2 ...