题目链接:

[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]斑斓之地——可持久化线段树的更多相关文章

  1. PYOJ 44. 【HNSDFZ2016 #6】可持久化线段树

    #44. [HNSDFZ2016 #6]可持久化线段树 统计 描述 提交 自定义测试 题目描述 现有一序列 AA.您需要写一棵可持久化线段树,以实现如下操作: A v p x:对于版本v的序列,给 A ...

  2. 【BZOJ-3673&3674】可持久化并查集 可持久化线段树 + 并查集

    3673: 可持久化并查集 by zky Time Limit: 5 Sec  Memory Limit: 128 MBSubmit: 1878  Solved: 846[Submit][Status ...

  3. 【BZOJ-2653】middle 可持久化线段树 + 二分

    2653: middle Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1298  Solved: 734[Submit][Status][Discu ...

  4. HDU 4866 Shooting(持久化线段树)

    view code//第二道持久化线段树,照着别人的代码慢慢敲,还是有点不理解 #include <iostream> #include <cstdio> #include & ...

  5. 【BZOJ-3653】谈笑风生 DFS序 + 可持久化线段树

    3653: 谈笑风生 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 628  Solved: 245[Submit][Status][Discuss] ...

  6. 【BZOJ3673】&&【BZOJ3674】: 可持久化并查集 by zky 可持久化线段树

    没什么好说的. 可持久化线段树,叶子节点存放父亲信息,注意可以规定编号小的为父亲. Q:不是很清楚空间开多大,每次询问父亲操作后修改的节点个数是不确定的.. #include<bits/stdc ...

  7. 【BZOJ3207】花神的嘲讽计划I 可持久化线段树/莫队

    看到题目就可以想到hash 然后很自然的联想到可持久化权值线段树 WA:base取了偶数 这道题还可以用莫队做,比线段树快一些 可持久化线段树: #include<bits/stdc++.h&g ...

  8. 【BZOJ 3674】可持久化并查集加强版&【BZOJ 3673】可持久化并查集 by zky 用可持久化线段树破之

    最后还是去掉异或顺手A了3673,,, 并查集其实就是fa数组,我们只需要维护这个fa数组,用可持久化线段树就行啦 1:判断是否属于同一集合,我加了路径压缩. 2:直接把跟的值指向root[k]的值破 ...

  9. 【BZOJ 3524】【Poi2014】Couriers 可持久化线段树

    为什么这个主席树叫可持久化线段树,我不知道,具体得问达神.我无限T,然后DaD3zZ一针见血地指出了我的N*50爆内存导致无限编译超时O)ZO)ZO)Z真是太神啦.以图为鉴: 达神题解传送门:http ...

随机推荐

  1. 博弈论进阶之Every-SG

    Every-SG 给定一张无向图,上面有一些棋子,两个顶尖聪明的人在做游戏,每人每次必须将可以移动的棋子进行移动,不能移动的人输 博弈分析 题目中的要求实际是"不论前面输与否,只要最后一个棋 ...

  2. Python开发爬虫之理论篇

    爬虫简介 爬虫:一段自动抓取互联网信息的程序. 什么意思呢? 互联网是由各种各样的网页组成.每一个网页对应一个URL,而URL的页面上又有很多指向其他页面的URL.这种URL之间相互的指向关系就形成了 ...

  3. 集成Android人脸识别demo分享

    本应用来源于虹软人工智能开放平台,人脸识别技术工程如何使用? 1.下载代码 git clone https://github.com/andyxm/ArcFaceDemo.git 2.下载虹软人脸识别 ...

  4. 新更新,又是一年了。这次记录下关于android版的WeiboDemo的问题

    时隔一年多,现在又开始折腾android的代码了.之前看了Learning android,就想看下能否移植到Weibo.然后就下了weibo的代码,代码包里有个实例叫WeiboSDKDemo. 为了 ...

  5. Unity协程的坑

    unity终止协程提供了  StopAllCoroutines() 和 StopCoroutines() 两个方法, 但是都只能终止该文件内的 IEnumerator. 并且具体使用有点坑, 见如下实 ...

  6. 电脑一键U盘启动快捷键

    下面是我特意列出的品牌电脑.笔记本电脑.组装电脑一键U盘启动快捷键对应列表,仅供大家查阅参考! [品牌-笔记本电脑] 笔记本品牌  启动按键 联想笔记本  F12 宏基笔记本  F12 华硕笔记本   ...

  7. navicat 将自增长字段重置(重新从1开始)的方法

    先说明,此语句会将你的表中数据全部删除. 很简单,运行如下sql语句: TRUNCATE TABLE 表名;

  8. LeetCode算法题-Detect Capital(Java实现)

    这是悦乐书的第251次更新,第264篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第118题(顺位题号是520).给定一个单词,你需要判断其中大写字母的使用是否正确.当下 ...

  9. 如何用Nginx解决前端跨域问题?

    前言 在开发静态页面时,类似Vue的应用,我们常会调用一些接口,这些接口极可能是跨域,然后浏览器就会报cross-origin问题不给调. 最简单的解决方法,就是把浏览器设为忽略安全问题,设置--di ...

  10. Python基础之协程

    阅读目录 一 引子 二 协程介绍 三 Greenlet模块 四 Gevent模块 引子 之前我们学习了线程.进程的概念,了解了在操作系统中 进程是资源分配的最小单位,线程是CPU调度的最小单位. 按道 ...