洛谷题面传送门

七月份(7.31)做的题了,题解到现在才补,不愧是 tzc

首先不难发现题目中涉及的变量都是布尔型变量,因此可以考虑 2-SAT,具体来说,我们将每个人在每个时刻的可能的状态表示出来。我们开两个二维变量 \(\text{Live}(i,t)\) 表示第 \(i\) 个人第 \(t\) 个时刻还活着,\(\text{Dead}(i,t)\) 则表示第 \(i\) 个人在第 \(t\) 个时刻已经死了,那么题目给出的条件即对应这些布尔变量的一些推导关系,具体来说:

  • 由于一个人死了不能复活,所以必有 \(\text{Dead}(i,t)\to\text{Dead}(i,t+1)\),同样地有逆否命题 \(\text{Live}(i,t+1)\to\text{Live}(i,t)\)
  • 对于条件 \(0\)​,显然可以连边 \(\text{Dead}(x,t)\to\text{Dead}(y,t+1)\),同理逆否命题 \(\text{Alive}(y,t+1)\to\text{Alive}(x,t)\)
  • 对于条件 \(1\),显然可以连边 \(\text{Alive}(x,t)\to\text{Dead}(y,t)\),同理逆否命题 \(\text{Alive}(y,t)\to\text{Dead}(x,t)\)

那么我们只要对建出来的图跑一遍 Tarjan,那么对于一个 \(i\)​​​,可能与它活到 \(T+1\)​​​ 时刻的居民数就是 \(n-1\)​​​ 再减去满足 \(\text{Alive}(i,T+1)\)​​​ 可以推到 \(\text{Dead}(j,T+1)\)​​​ 的居民 \(j\)​​​ 的数量。注意,如果一个居民 \(j\)​​​ 满足 \(\text{Alive}(j,T+1)\)​​​ 可以推到 \(\text{Dead}(j,T+1)\)​​​,那么它无论如何在 \(T+1\)​​​ 时刻都是死亡状态,对于这样的居民我们特判一下即可,具体来说,我们对于每个 \(i\)​​​ 去掉 \(\text{Alive}(i,T+1)\)​​​ 可以推到 \(\text{Dead}(j,T+1)\)​​​ 的点 \(j\)​​​ 的数量后,还需去掉满足 \(\text{Alive}(i,T+1)\)​​​ 推不到 \(\text{Dead}(j,T+1)\)​​​,但 \(\text{Alive}(j,T+1)\)​​​ 可以推到 \(\text{Dead}(j,T+1)\) 的 \(j\) 的数量​​​。

这样暴力做空间复杂度是平方的,时间复杂度是三方的,一脸过不去的样子,因此考虑优化,首先可以注意到一件事情就是我们其实并不需要缩点,因为在连出来的这张图中,只存在 \(\text{Alive}\to\text{Alive},\text{Dead}\to\text{Alive},\text{Dead}\to\text{Dead}\) 的边,并且 \(\text{Alive}\) 的边只会从时间后的连向时间前的,\(\text{Dead}\) 的边只会从时间前的连向时间后的,因此原图本身就是一个 DAG。其次,不难发现原图中很多点其实是没有用的,具体来说,我们只需要保留条件中的 \((x,t)\) 和 \((i,T+1)\),其他点都可以去掉,这样点数就降到了 \(\mathcal O(n+m)\),空间复杂度也就降了下来。

但是这样时间复杂度还是会爆炸,不过注意到此题我们只关心两个点之间的可达性,也就是一个取值只有 \(0/1\)​​​ 的布尔型变量,因此可以非常自然地想到 bitset,具体来说我们以每个 \((i,T+1)\)​​​ 为起点进行一边 DFS 找出它能够到达哪些 \(\text{Dead}(i,T+1)\)​​​,用一个 bitset 维护,每次转移就遍历与当前点相邻的点然后令该点的答案或上与其相连的点的答案即可,由于加了记忆化搜索,因此我们每个点最多计算一次,复杂度就是 \(\mathcal O(\dfrac{(n+m)^2}{\omega})\)​,但这样空间复杂度又爆掉了。因此考虑一个据说非常 common 的套路:分块 DFS,具体来说我们每 \(B\) 个元素一块,然后我们每次处理每一块中的 \(\text{Dead}(i,T+1)\) 对所有点的贡献,这样我们 bitset 的大小只用开到 \(B\),时间复杂度 \(\mathcal O(\dfrac{n^2}{\omega}+\dfrac{n^2}{B})\),空间复杂度 \(\dfrac{nB}{\omega}\),取 \(B=10^4\) 时最优。

const int MAXN=5e4;
const int MAXM=1e5;
const int MAXV=3e5;
const int MAXE=1e6;
const int BLK=1e4;
int n,m,T,ncnt;set<int> nd[MAXN+5];
struct data{int opt,t,x,y;} a[MAXM+5];
map<int,int> id[2][MAXN+5];
int hd[MAXV+5],nxt[MAXE+5],to[MAXE+5],ec=0;
void adde(int u,int v){to[++ec]=v;nxt[ec]=hd[u];hd[u]=ec;}
int lv[MAXN+5],dd[MAXN+5],bel[MAXV+5],res[MAXN+5];
bitset<MAXN+5> must;
bitset<MAXV+5> vis;
bitset<BLK+5> st[MAXV+5];
void dfs(int x,int l,int r){
if(vis.test(x)) return;vis.set(x);st[x].reset();
if(l<=bel[x]&&bel[x]<=r) st[x].set(bel[x]-l+1);
for(int e=hd[x];e;e=nxt[e]){
int y=to[e];dfs(y,l,r);
st[x]|=st[y];
}
}
int main(){
scanf("%d%d%d",&T,&n,&m);
for(int i=1;i<=m;i++) scanf("%d%d%d%d",&a[i].opt,&a[i].t,&a[i].x,&a[i].y);
for(int i=1;i<=n;i++) nd[i].insert(T+1);
for(int i=1;i<=m;i++) nd[a[i].x].insert(a[i].t);
for(int i=1;i<=n;i++){
for(int x:nd[i]) id[0][i][x]=++ncnt,id[1][i][x]=++ncnt;
int pre0=0,pre1=0;
for(int x:nd[i]){
int cur0=id[0][i][x],cur1=id[1][i][x];
if(pre0) adde(pre0,cur0),adde(cur1,pre1);
pre0=cur0;pre1=cur1;
}
}
for(int i=1;i<=m;i++){
if(!a[i].opt){
int tt=*nd[a[i].y].upper_bound(a[i].t);
adde(id[0][a[i].x][a[i].t],id[0][a[i].y][tt]);
adde(id[1][a[i].y][tt],id[1][a[i].x][a[i].t]);
} else {
int tt=*nd[a[i].y].lower_bound(a[i].t);
adde(id[1][a[i].x][a[i].t],id[0][a[i].y][tt]);
adde(id[1][a[i].y][tt],id[0][a[i].x][a[i].t]);
}
}
for(int i=1;i<=n;i++){
lv[i]=id[1][i][T+1];
dd[i]=id[0][i][T+1];bel[dd[i]]=i;
}
for(int l=1,r=BLK;l<=n;l+=BLK,r+=BLK){
chkmin(r,n);vis.reset();bitset<BLK+5> cur;
for(int i=1;i<=n;i++) dfs(lv[i],l,r);
for(int i=l;i<=r;i++) if(st[lv[i]].test(i-l+1)) must.set(i),cur.set(i-l+1);
for(int i=1;i<=n;i++) res[i]+=r-l+1-(st[lv[i]]|cur).count();
}
for(int i=1;i<=n;i++) printf("%d%c",(must.test(i))?0:(res[i]-1)," \n"[i==n]);
return 0;
}

洛谷 P5332 - [JSOI2019]精准预测(2-SAT+bitset+分块处理)的更多相关文章

  1. [LOJ 3101] [Luogu 5332] [JSOI2019]精准预测(2-SAT+拓扑排序+bitset)

    [LOJ 3101] [Luogu 5332] [JSOI2019]精准预测(2-SAT+拓扑排序+bitset) 题面 题面较长,略 分析 首先,发现火星人只有死和活两种状态,考虑2-SAT 建图 ...

  2. 【JSOI2019】精准预测(2-SAT & bitset)

    Description 现有一台预测机,可以预测当前 \(n\) 个人在 \(T\) 个时刻内的生死关系.关系有两种: \(\texttt{0 t x y}\):如果 \(t\) 时刻 \(x\) 死 ...

  3. [JSOI2019]精准预测

    题目 这么明显的限制条件显然是\(\text{2-sat}\) 考虑按照时间拆点,\((0/1,x,t)\)表示\(x\)个人在时间\(t\)是生/死 有一些显然的连边 \[(0,x,t+1)-> ...

  4. [JSOI2019]精准预测(2-SAT+拓扑排序+bitset)

    设第i个人在t时刻生/死为(x,0/1,t),然后显然能够连上(x,0,t)->(x,0,t-1),(x,1,t)->(x,1,t+1),然后对于每个限制,用朴素的2-SAT连边即可. 但 ...

  5. [Bzoj5285][洛谷P4424][HNOI/AHOI2018]寻宝游戏(bitset)

    P4424 [HNOI/AHOI2018]寻宝游戏 某大学每年都会有一次Mystery Hunt的活动,玩家需要根据设置的线索解谜,找到宝藏的位置,前一年获胜的队伍可以获得这一年出题的机会. 作为新生 ...

  6. 洛谷 - P2257 - YY的GCD - 莫比乌斯反演 - 整除分块

    https://www.luogu.org/problemnew/show/P2257 求 \(n,m\) 中 \(gcd(i,j)==p\) 的数对的个数 求 $\sum\limits_p \sum ...

  7. 洛谷 - UVA11424 - GCD - Extreme (I) - 莫比乌斯反演 - 整除分块

    https://www.luogu.org/problemnew/show/UVA11424 原本以为是一道四倍经验题来的. 因为输入的n很多导致像之前那样 \(O(n)\) 计算变得非常荒谬. 那么 ...

  8. 洛谷P4135 作诗(不一样的分块)

    题面 给定一个长度为 n n n 的整数序列 A A A ,序列中每个数在 [ 1 , c ] [1,c] [1,c] 范围内.有 m m m 次询问,每次询问查询一个区间 [ l , r ] [l, ...

  9. 【LOJ】#3101. 「JSOI2019」精准预测

    LOJ#3101. 「JSOI2019」精准预测 设0是生,1是死,按2-sat连边那么第一种情况是\((t,x,1) \rightarrow (t + 1,y,1)\),\((t + 1,y, 0) ...

随机推荐

  1. [Java]Sevlet

    0 前言 对于Java程序员而言,Web服务器(如Tomcat)是后端开发绕不过去的坎.简单来看,浏览器发送HTTP请求给服务器,服务器处理后发送HTTP响应给浏览器. Web服务器负责对请求进行处理 ...

  2. airtest keyevent 按键速查表

  3. 【二食堂】Beta - Scrum Meeting 11

    Scrum Meeting 11 例会时间:5.26 18:30~18:50 进度情况 组员 当前进度 今日任务 李健 1. 文本导入.保存部分的工作比想象中的难,还需要一些时间完成issue 1. ...

  4. Noip模拟7 2021.6.11

    前言 考试时候der展了,T1kmp没特判(看来以后还是能hash就hash),T2搜索细节没注意,ans没清零,130飞到14.... T1 匹配(hash/kmp) 这太水了,其实用个hash随便 ...

  5. 大神教零基础入门如何快速高效的学习c语言开发

    零基础如果更快更好的入门C语言,如何在枯燥的学习中找到属于自己的兴趣,如果把学习当成一种事务性的那以后的学习将会很难有更深入的进步,如果带着乐趣来完成学习那将越学越有意思这样才会让你有想要更深入学习的 ...

  6. IdentityServer4 负载均衡配置

    在不用到负载之前,一切都很好,但是部署多个实例之后,问题挺多的:session问题.令牌签发后的校验问题. 在此之前,先自查官方文档:Deployment - IdentityServer4 1.0. ...

  7. Py高级函数和方法

    Map() Redece() Dir() __len__   ---->>>  len() getattr().setattr() 以及   hasattr() 参考廖雪峰----- ...

  8. 翻转子串 牛客网 程序员面试金典 C++ Python

    反转子串 牛客网 程序员面试金典 C++ Python 题目描述 假定我们都知道非常高效的算法来检查一个单词是否为其他字符串的子串.请将这个算法编写成一个函数,给定两个字符串s1和s2,请编写代码检查 ...

  9. centos 下安装docker

    官方文档比较累赘,简化就三步 1.安装依赖 yum -y install gcc gcc-c++ yum-utils device-mapper-persistent-data lvm2 2.添加re ...

  10. 重装系统——联想window 10

    大四了,读了四年大学,唉,混的,啥也不会,工作也找不到,真的不知道这大学四年到底干了什么.专业是计算机方向的,但居然,不敢,也不会装电脑系统,大学四年的文件都是乱放的,更那个的是,有些软件卸载不完全, ...