【ZJOI2012】小蓝的好友(mrx)
来源:互联网 发布:迈锐宝xl怎么样知乎 编辑:程序博客网 时间:2024/05/02 00:04
Description
终于到达了这次选拔赛的最后一题,想必你已经厌倦了小蓝和小白的故事,为了回馈各位比赛选手,此题的主角是贯穿这次比赛的关键人物——小蓝的好友。
在帮小蓝确定了旅游路线后,小蓝的好友也不会浪费这个难得的暑假。与小蓝不同,小蓝的好友并不想将时间花在旅游上,而是盯上了最近发行的即时战略游戏——SangoCraft。但在前往通关之路的道路上,一个小游戏挡住了小蓝的好友的步伐。
“国家的战争其本质是抢夺资源的战争”是整款游戏的核心理念,这个小游戏也不例外。简单来说,用户需要在给定的长方形土地上选出一块子矩形,而系统随机生成了N个资源点,位于用户所选的长方形土地上的资源点越多,给予用户的奖励也越多。悲剧的是,小蓝的好友虽然拥有着极其优秀的能力,但同时也有着极差的RP,小蓝的好友所选的区域总是没有一个资源点。
终于有一天,小蓝的好友决定投诉这款游戏的制造厂商,为了搜集证据,小蓝的好友想算出至少包含一个资源点的区域的数量。作为小蓝的好友,这自然是你分内之事。
Solution
笛卡尔树
开始还以为这是单调栈什么的,但是好大啊……
想到单调栈有些其实可以用笛卡尔树来实现。
先转化思路
很容易想到用矩阵数的总数减去空白矩阵的总数。
假如一个矩阵的长为a和b,那么含有的矩阵数为
想一想扫描线
从下往上开始扫描,那么我们只要存储每个点最大向上的距离和涵盖的最大矩阵的宽度就可以了。
如何找这一个矩阵
首先我们建立一棵笛卡尔树(我这里用treap来打,因为treap的最小堆性质让它是一个笛卡尔树),每个节点存储key(这个节点最大向上的高度),存储size(这个节点向左右的最大宽度,因为用笛卡尔树来存储,那么size就是子节点的个数),存储sum(这个节点的子节点的贡献总和,不包括当前的这个节点)。
很显然每次碰到一个黑点,就把在树中的这个节点的key清0,然后再把它旋转到根节点,那么它在高度为0时就可以涵盖所有的节点。
那么这个节点的父节点之间的答案贡献就是
每次再给root的key+1并打个懒标记就好了。
Code
#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>#define fo(i,a,b) for(i=a;i<=b;i++)#define rep(i,a) for(i=first[a];i;i=next[i])using namespace std;const int maxn=100007;typedef long long ll;int i,j,k,l,n,m,c;int first[maxn],last[maxn],next[maxn],num,root,t[maxn][2];int size[maxn];ll key[maxn],sum[maxn],add[maxn],ans;void add1(int x,int y){ last[++num]=y;next[num]=first[x];first[x]=num;}ll suan(int x){return x*(x+1)/2;}void back(int x,int y){ key[x]+=y;add[x]+=y;}void update(int x){ size[x]=1;sum[x]=0; if(t[x][0]){ size[x]+=size[t[x][0]]; sum[x]+=sum[t[x][0]]+suan(size[t[x][0]])*(key[t[x][0]]-key[x]); } if(t[x][1]){ size[x]+=size[t[x][1]]; sum[x]+=sum[t[x][1]]+suan(size[t[x][1]])*(key[t[x][1]]-key[x]); }}void build(int &x,int l,int r){ if(l>r){x=0;return;} int mid=(l+r)/2; x=mid; build(t[x][0],l,mid-1); build(t[x][1],mid+1,r); update(x);}void remove(int x){ if(add[x]){ if(t[x][0])back(t[x][0],add[x]); if(t[x][1])back(t[x][1],add[x]); update(x); add[x]=0; }}void rotate(int &x,int z){ int y=t[x][z]; t[x][z]=t[y][1-z]; t[y][1-z]=x; update(x);update(y); x=y;}void change(int &x,int y){ remove(x); if(y==size[t[x][0]]+1){ key[x]=0; update(x); return; } if(y<size[t[x][0]]+1){ change(t[x][0],y); rotate(x,0); } else{ change(t[x][1],y-size[t[x][0]]-1); rotate(x,1); }}int main(){ scanf("%d%d%d",&n,&m,&c); fo(i,1,c){ scanf("%d%d",&k,&l); add1(k,l); } ans=suan(n)*suan(m); build(root,1,m); fo(j,1,n){ back(root,1); rep(i,j){ change(root,last[i]); } ans-=sum[root]+suan(size[root])*key[root]; } printf("%lld\n",ans);}
- bzoj2658: [Zjoi2012]小蓝的好友(mrx)
- bzoj2658: [Zjoi2012]小蓝的好友(mrx)
- 【ZJOI2012】小蓝的好友(mrx)
- BZOJ2658 [Zjoi2012]小蓝的好友(mrx)
- bzoj 2658: [Zjoi2012]小蓝的好友(mrx) Treap
- BZOJ 2658 [Zjoi2012]小蓝的好友(mrx)
- [Treap 笛卡尔树 扫描线 补集转化] BZOJ 2658 [Zjoi2012]小蓝的好友(mrx)
- bzoj 2658: [Zjoi2012]小蓝的好友(mrx) treap+扫描线
- [bzoj2658]小蓝的好友
- 发现校内网好友买卖的一个小漏洞!并成功实现自动好友买卖!
- 通过QQ小秘书与任意好友聊天的源程序
- 获取QQ所有在线好友IP的小技巧
- 微信好友名字里加入小图标的方法
- 【小白的CFD之旅】03 老蓝
- [BZOJ2657][Zjoi2012]旅游(journey) 树的直径
- [BZOJ 2657][Zjoi2012]旅游(journey):树的直径
- 一个好友的收藏。小洪(洪承煜),不打招呼就转载一下罗,呵呵
- 微信的两个小功能------“摇一摇搜歌”和“雷达加好友”确实打动了我
- JAVA基础(第一天 安装JDK)
- 算术编码转载2
- hello world (android mediaplayer)
- 网络访问请求:中文空格字符解码
- linux创建PHP定时任务
- 【ZJOI2012】小蓝的好友(mrx)
- User Interest Profiling from User Generated Visual Content----论文笔记
- word怎么转换成pdf文档——两种转换方法分享
- JavaScript学习——web通信长连接
- [hdu1561] The more, The Better 【树形DP】
- openSuse linux下安装升级ftp服务
- Excel文档处理之Open XML
- Linux系统如何查看及修改文件读写权限
- Android 基于Message的进程间通信 Messenger完全解析