[LOJ2310][APIO2017]斑斓之地——可持久化线段树
题目链接:
将不是河流的格子染成白色,是河流的格子染成黑色,那么连通块数就是白色格子数$-1*2$的联通白色格子数$-2*1$的联通白色格子数$+2*2$的联通白色格子数。
我们考虑每个格子与它左边、上边、左上三个格子的连通性(同为白色视为联通)。
为了方便起见,对于每个$2*2$的格子,我们将它编号,从左往右、从上往下依次编号为$1,2,3,4$。
我们将$1,2,3$与$4$的连通性都归为$4$号格子对答案的贡献。
显然联通情况有$5$种:$1,2,3,4$、$2,3,4$、$2,4$、$3,4$、$4$。
对于第一种情况,$4$号点对答案的贡献为$1-1-1+1=0$
对于第二种情况,$4$号点对答案的贡献为$1-1-1=-1$
对于第三、四种情况,$4$号点对答案的贡献为$1-1=0$
对于第五种情况,$4$号点对答案的贡献为$1$
可以发现第一、三、四种情况对答案没有影响,而第二、五种情况只会出现在一个连通块的最左边和最上边两排(有一种特殊情况后边再说明)。
对于最左边,如果有一个格子是第二种情况,那么在这个点的同一行的最左边那个点就会是第五种情况,这两个格子的贡献抵消。
对于最上边,如果有一个格子是第二种情况,那么在这个点的同一列的最上边那个点就会是第五种情况,这两个格子的贡献抵消。
但可以发现最左上的那个格子是第五种情况却没有其他格子与它的贡献抵消,所以只有这个格子对这个连通块有贡献。
这样有一个特例就是河流被这个连通块包围起来,即这个连通块是中空的。
那么右边和下边也会出现第二、五种情况,而对于右下两部分格子中的左上那个格子是第二种情况,会将上面那个对连通块有贡献的格子抵消掉(如下图所示),所以对于这种情况特判一下将答案加一即可。

剩下的就是如何统计上述的四种连通块的个数。
因为地图总大小是$4*10^{10}$,无法对每个点存是否有上述四种贡献。
但可以发现河流的格子最多只有$2*10^5$个格子,我们分别记录哪些格子没有上述四种贡献,然后用总贡献减一下即可。
对于整个地图将横坐标作为版本,对纵坐标建线段树即建立四棵可持久化线段树分别维护上述四种信息。
注意彩虹蛇可能走之前走过的格子,要判重避免重复统计。
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<vector>
#include<bitset>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
int n,m,q,k;
map<int,int>mp[200010];
int px[200010];
int py[200010];
int tot;
int mx1,mx2,mn1,mn2;
int fx,fy;
int size;
vector<int>t1[200010];
vector<int>t2[200010];
vector<int>t3[200010];
vector<int>t4[200010];
char ch[200010];
int a,b,c,d;
ll ans;
struct lty
{
int cnt;
int root[200010];
int ls[4000010];
int rs[4000010];
int sum[4000010];
void updata(int &rt,int pre,int l,int r,int k)
{
rt=++cnt;
ls[rt]=ls[pre];
rs[rt]=rs[pre];
sum[rt]=sum[pre]+1;
if(l==r)
{
return ;
}
int mid=(l+r)>>1;
if(k<=mid)
{
updata(ls[rt],ls[pre],l,mid,k);
}
else
{
updata(rs[rt],rs[pre],mid+1,r,k);
}
}
int query(int x,int y,int l,int r,int L,int R)
{
if(!y)
{
return 0;
}
if(L<=l&&r<=R)
{
return sum[y]-sum[x];
}
int mid=(l+r)>>1;
int res=0;
if(L<=mid)
{
res+=query(ls[x],ls[y],l,mid,L,R);
}
if(R>mid)
{
res+=query(rs[x],rs[y],mid+1,r,L,R);
}
return res;
}
}tr1,tr2,tr3,tr4;
int main()
{
scanf("%d%d%d%d",&n,&m,&k,&q);
scanf("%d%d",&fx,&fy);
tot++;
px[tot]=fx,py[tot]=fy;
mx1=mn1=fx,mx2=mn2=fy;
mp[fx][fy]=1;
if(k)
{
scanf("%s",ch+1);
}
for(int i=1;i<=k;i++)
{
tot++;
if(ch[i]=='N')
{
fx--;
}
else if(ch[i]=='S')
{
fx++;
}
else if(ch[i]=='E')
{
fy++;
}
else
{
fy--;
}
px[tot]=fx,py[tot]=fy;
mx1=max(mx1,fx);
mn1=min(mn1,fx);
mx2=max(mx2,fy);
mn2=min(mn2,fy);
mp[fx][fy]=1;
}
for(int i=1;i<=tot;i++)
{
int x=px[i],y=py[i];
if(mp[x][y]==2)
{
continue;
}
mp[x][y]=2;
t1[x].push_back(y);
if(y>1)t2[x].push_back(y);
if(y<m&&!mp[x][y+1])t2[x].push_back(y+1);
if(x>1)t3[x].push_back(y);
if(x<n&&!mp[x+1][y])t3[x+1].push_back(y);
if(x>1&&y>1)t4[x].push_back(y);
if(x<n&&y<m&&!mp[x+1][y+1])t4[x+1].push_back(y+1);
if(x<n&&y>1&&!mp[x][y-1]&&!mp[x+1][y])t4[x+1].push_back(y);
if(x>1&&y<m&&!mp[x-1][y]&&!mp[x-1][y+1]&&!mp[x][y+1])t4[x].push_back(y+1);
}
for(int i=1;i<=n;i++)
{
tr1.root[i]=tr1.root[i-1];
tr2.root[i]=tr2.root[i-1];
tr3.root[i]=tr3.root[i-1];
tr4.root[i]=tr4.root[i-1];
size=t1[i].size();
for(int j=0;j<size;j++)
{
tr1.updata(tr1.root[i],tr1.root[i],1,m,t1[i][j]);
}
size=t2[i].size();
for(int j=0;j<size;j++)
{
tr2.updata(tr2.root[i],tr2.root[i],1,m,t2[i][j]);
}
size=t3[i].size();
for(int j=0;j<size;j++)
{
tr3.updata(tr3.root[i],tr3.root[i],1,m,t3[i][j]);
}
size=t4[i].size();
for(int j=0;j<size;j++)
{
tr4.updata(tr4.root[i],tr4.root[i],1,m,t4[i][j]);
}
}
while(q--)
{
scanf("%d%d%d%d",&a,&b,&c,&d);
ans=0;
if(a<mn1&&c>mx1&&b<mn2&&d>mx2)
{
ans++;
}
ans+=1ll*(d-b)*(c-a)-tr1.query(tr1.root[a-1],tr1.root[c],1,m,b,d);
ans-=1ll*(d-b-1)*(c-a)-tr2.query(tr2.root[a-1],tr2.root[c],1,m,b+1,d);
ans-=1ll*(d-b)*(c-a-1)-tr3.query(tr3.root[a],tr3.root[c],1,m,b,d);
ans+=1ll*(d-b-1)*(c-a-1)-tr4.query(tr4.root[a],tr4.root[c],1,m,b+1,d);
printf("%lld\n",ans);
}
return 0;
}
[LOJ2310][APIO2017]斑斓之地——可持久化线段树的更多相关文章
- PYOJ 44. 【HNSDFZ2016 #6】可持久化线段树
#44. [HNSDFZ2016 #6]可持久化线段树 统计 描述 提交 自定义测试 题目描述 现有一序列 AA.您需要写一棵可持久化线段树,以实现如下操作: A v p x:对于版本v的序列,给 A ...
- 【BZOJ-3673&3674】可持久化并查集 可持久化线段树 + 并查集
3673: 可持久化并查集 by zky Time Limit: 5 Sec Memory Limit: 128 MBSubmit: 1878 Solved: 846[Submit][Status ...
- 【BZOJ-2653】middle 可持久化线段树 + 二分
2653: middle Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 1298 Solved: 734[Submit][Status][Discu ...
- HDU 4866 Shooting(持久化线段树)
view code//第二道持久化线段树,照着别人的代码慢慢敲,还是有点不理解 #include <iostream> #include <cstdio> #include & ...
- 【BZOJ-3653】谈笑风生 DFS序 + 可持久化线段树
3653: 谈笑风生 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 628 Solved: 245[Submit][Status][Discuss] ...
- 【BZOJ3673】&&【BZOJ3674】: 可持久化并查集 by zky 可持久化线段树
没什么好说的. 可持久化线段树,叶子节点存放父亲信息,注意可以规定编号小的为父亲. Q:不是很清楚空间开多大,每次询问父亲操作后修改的节点个数是不确定的.. #include<bits/stdc ...
- 【BZOJ3207】花神的嘲讽计划I 可持久化线段树/莫队
看到题目就可以想到hash 然后很自然的联想到可持久化权值线段树 WA:base取了偶数 这道题还可以用莫队做,比线段树快一些 可持久化线段树: #include<bits/stdc++.h&g ...
- 【BZOJ 3674】可持久化并查集加强版&【BZOJ 3673】可持久化并查集 by zky 用可持久化线段树破之
最后还是去掉异或顺手A了3673,,, 并查集其实就是fa数组,我们只需要维护这个fa数组,用可持久化线段树就行啦 1:判断是否属于同一集合,我加了路径压缩. 2:直接把跟的值指向root[k]的值破 ...
- 【BZOJ 3524】【Poi2014】Couriers 可持久化线段树
为什么这个主席树叫可持久化线段树,我不知道,具体得问达神.我无限T,然后DaD3zZ一针见血地指出了我的N*50爆内存导致无限编译超时O)ZO)ZO)Z真是太神啦.以图为鉴: 达神题解传送门:http ...
随机推荐
- embed 引入网上视频
<p>embed引入网上视频</p> <embed src='http://player.youku.com/player.php/sid/XMjgxODkyMTIxNg ...
- Android八门神器(一): OkHttp框架源码解析
HTTP是我们交换数据和媒体流的现代应用网络,有效利用HTTP可以使我们节省带宽和更快地加载数据,Square公司开源的OkHttp网络请求是有效率的HTTP客户端.之前的知识面仅限于框架API的调用 ...
- 第三篇 Html-label标签
label标签 用户获取文字,使得关联的标签获取光标 <!DOCTYPE html> <html lang="en"> <head> <m ...
- 使用 Dashboard - 每天5分钟玩转 Docker 容器技术(174)
上一节我们完成了 Kubernetes Dashboard 的安装,本节就来实践一下. Dashboard 界面结构 Dashboard 的界面很简洁,分为三个大的区域. 顶部操作区在这里用户可以搜索 ...
- Oracle根据符合条件的数据循环批量更新
--批量对符合条件的表记录进行更新 --aa代表查询出的符合条件数据的别名 --aa后的表示需要符合的条件 --loop后开始写更新操作 begin for aa in (select a.objec ...
- SQLServer之创建隐式事务
隐式事务创建注意事项 IMPLICIT_TRANSACTIONS为 ON 时,系统处于“隐式”事务模式. 这意味着如果 @@TRANCOUNT = 0,下列任一 Transact-SQL 语句都会开始 ...
- 【原】Java学习笔记022 - 字符串
package cn.temptation; public class Sample01 { public static void main(String[] args) { // 字符串 // 定义 ...
- Linux(Deepin 15.9) - MySQL5.7 安装
Linux(Deepin 15.9) - MySQL5.7 安装 sudo apt install mysql-server/panda sudo apt install mysql-client/p ...
- python3 str(字符串)
__add__函数 (在后面追加字符串) s1 ='Hello' s2 = s1.__add__(' boy!') print(s2) #输出:Hello boy! __contains__(判断是否 ...
- Java操作Excel(使用POI)
背景说明 以前写过使用 JXL 操作Excel的例子,但JXL对于Excel 2007版本以后的文件(即扩展名为 .xlsx)无法读取,也找不到可以支持的包.所以,有时不得不用 POI 来操作Exce ...