题面



$ solution: $

真的没有想到可以用分块。

但是可以发现一个性质,每个询问只关心这个点最后一次赋值操作,和这个赋值操作后的所有取 $ min $ 操作。这个感觉很有用,但是真的很难让人想到低于 $ n\times m $ 的做法。基于 $ DAG $ 的数据结构是目前很少需要掌握的(好吧我都不知道有什么数据结构可以维护 $ DAG $ )所以肯定得骚操作。

我们可以发现一个 $ DAG $ 的性质,如果有一连串赋值操作我们可以根据拓扑序 $ O(n) $ 将所有操作完成,直接按顺序从后往前赋值,这样每个点赋值之后就不会再被访问。同理的, 如果有一连串取 $ min $ 操作我们也可以根据拓扑序 $ O(n) $ 将所有操作完成,直接 $ min $ 值从小到大取 $ min $, 这样每个点在取 $ min $ 之后就不会再被访问。但是当我们将这两种操作合到一起时就不行了。

但是联想一下上面说的性质:每个询问只关心这个点最后一次赋值操作,和这个赋值操作后的所有取 $ min $ 操作。我们可以搞出一个分块来,先预处理2操作,将2操作序列分块,并将每一块用上面的方法统计出每个结点在每个块内的取 $ min $ 后的值(初值inf)。然后我们就可以 $ \sqrt{n} $ 的求出任意一个区间里某个节点取 $ min $ 的最小值(其实还需要一个操作)。然后我们只需要快速找到每个询问的节点的最后一次赋值操作的编号,即赋值的大小,就可以得到答案。找到这个编号,我们可以对1操作分块来完成。

但是上述操作我们还需要知道一个东西,因为分块两边的小区间是要暴力遍历的,这个我们需要知道每个操作能否对某个点产生影响,这个等同于我们要知道 $ DAG $ 中一个点能否到另一个点。这个很奇妙的我们可以用 $ bitset $ 暴力完成。因为这个是无法用低于 $ n\times m $ 的复杂度完成,但是只涉及能否我们可以用二进制

  1. 仔细分析求得答案需要什么关键信息
  2. 对于一连串操作可以一次完成,就考虑分治或分块
  3. 对于两种操作会互相影响,考虑先预处理一种操作在进行第二种操作
  4. 二进制和是与否,这个对于复杂度优化很好用。
  5. $ DAG $ 中的一些问题是难以用低于 $ n\times m $ 的做法完成的!



$ code: $

#include<iostream>
#include<cstdio>
#include<iomanip>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<ctime>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<bitset>#define ll long long
#define db double
#define rg register intusing namespace std;int tt,t=1;
int n,m,q,ff;
int a[100005];
int idx[100005];
int fq[100005];
int fm[100005][404];
int vis[100005];
bitset<100005> f[100005];struct su{int to,next;
}b[200005];
int tou[100005];struct pi{int id,x,v,op;inline bool operator <(const pi &i)const{return v<i.v;}
}s[100005],k[100005];inline int qr(){register char ch; register bool sign=0; rg res=0;while(!isdigit(ch=getchar()))if(ch=='-')sign=1;while(isdigit(ch))res=res*10+(ch^48),ch=getchar();if(sign)return -res; else return res;
}inline void yu(int i){ //预处理dag中两点是否可达vis[i]=1; f[i][i]=1;for(rg j=tou[i];j;j=b[j].next){if(!vis[b[j].to]) yu(b[j].to);f[i]|=f[b[j].to];}
}inline void dfs(int i,int v,int time,bool op){ //修改操作if(vis[i]==t)return ; else vis[i]=t; //根据op判断是1操作还是2操作if(op) a[i]=v,idx[i]=time; else fm[i][time]=v;for(rg j=tou[i];j;j=b[j].next){if(vis[b[j].to]==t)continue;dfs(b[j].to,v,time,op);}
}int main(){//freopen("dag.in","r",stdin);//freopen("dag.out","w",stdout);n=qr(); m=qr(); q=qr(); ff=sqrt(q-1)+1;for(rg i=1;i<=q;++i) fq[i]=(i-1)/ff+1; //分块for(rg i=1;i<=m;++i){rg x=qr(),y=qr();b[i]=su{y,tou[x]}; tou[x]=i;}for(rg i=1;i<=n;++i) if(!vis[i])yu(i);for(rg i=1;i<=q;++i){ //先预处理每个块内的2操作rg op=qr(); s[i]=pi{i,qr(),0,op};if(op<=2) s[i].v=qr();if(op==2) k[++tt]=s[i];if(fq[i]!=fq[i+1]){sort(k+1,k+tt+1); ++t; //从小到大,保证每个点只修改一次for(rg j=1;j<=n;++j) fm[j][fq[i]]=1e9; //赋初值for(rg j=1;j<=tt;++j)dfs(k[j].x,k[j].v,fq[i],0);tt=0;}}for(rg i=1;i<=q;++i){if(s[i].op==3){rg x=s[i].x,y=idx[x],v=a[x],sf=0;for(rg j=i;fq[j]==fq[i];--j){ //在同一个块内,暴力处理if(s[j].op==1&&f[s[j].x][x]){ sf=1; y=j; v=s[j].v;for(rg o=y;o<=i;++o)if(s[o].op==2&&f[s[o].x][x]) v=min(v,s[o].v);break;}}if(!sf){ //这个if调了半个上午for(rg j=y+1;fq[j]==fq[y];++j) //前小块if(s[j].op==2&&f[s[j].x][x]) v=min(v,s[j].v);for(rg j=fq[y]+1;j<=fq[i]-1;++j) v=min(v,fm[x][j]); //中间的大块for(rg j=i;fq[j]==fq[i];--j) //后小块if(s[j].op==2&&f[s[j].x][x]) v=min(v,s[j].v);}printf("%d\n",v);}if(fq[i]!=fq[i+1]){ ++t; //将这个块内的1操作一遍做完for(rg j=i;fq[j]==fq[i];--j)if(s[j].op==1)dfs(s[j].x,s[j].v,j,1);}}return 0;
}

转载于:https://www.cnblogs.com/812-xiao-wen/p/11505436.html

LOJ bitset+分块 大内存毒瘤题相关推荐

  1. 约会安排 (区间合并)毒瘤题

    约会安排 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others) Total Submi ...

  2. LOJ 数列分块入门6

    LOJ 数列分块入门6 题目: 题目 题解: 我都不懂这题为什么要用分块... ... 直接vector就好了... 但是如果有区间修改的话就不行了.所以这题是启示我们也可以动态分块.具体就是每次插入 ...

  3. 【考研】830 + 848 暨大2012-2022真题易混易错题总结(二)

    前言 以下题目,均源自于暨南大学 2012 - 2022 年的 830 + 848 真题.主要是对真题中易混易错题进行记录和总结. 分为三篇博文,此乃第二篇,真题是 2018 - 2020 年的,即 ...

  4. 一条SQL能占多大内存?

    初学计算机时,我经常琢磨的一个问题是:一个进程到底能吃多大内存,能把系统内存吃完? 学了数据库后,我又开始问自己类似的问题,一条 SQL 能把数据库内存全部吃完? 假设数据库系统内存 有128GB,全 ...

  5. 算法笔记(三)特殊数据结构——哈希表、有序表、并查集、KMP、Manacher、单调栈、位图、大数据类题

    layout: post title: 算法笔记(三)特殊数据结构--哈希表.有序表.并查集.KMP.Manacher.单调栈.位图.大数据类题 description: 算法笔记(三)特殊数据结构- ...

  6. RamDisk - 充分利用Vista的大内存

    RamDisk - 充分利用Vista的大内存,详细图文教程 最近看到很多坛友都在问关于RamDisk这款软件以及大内存如何使用的问题.首先来讲拥有大内存是好事情,但是众所周知32位的vista系统可 ...

  7. 64位大内存虚拟机Page File的存放位置

    系统Page File,用于Windows操作系统的缓存和debug,一般存放于C盘根目录下,当Windows操作系统出现蓝屏时,会将对应的内存dump写入系统Page File. 随着ESXi5.0 ...

  8. 毒瘤题No.006-byFHS

    毒瘤题No.006-byFHS 题目背景 暂无 题目描述 给你一个无向图,求最少用多少棵树来覆盖这个图上的所有边 输入格式 第1行:两个数\(n,m\),表示有\(n\)个点,\(m\)条边 接下来\ ...

  9. 家用计算机内存最大是多少,电脑支持最大内存是多少?选用多大内存才合理?方法技巧要知道...

    内存条 是电脑里面的一个硬件,它主要起到 运行处理CPU发出的指令 ,处理完毕后,再反馈给CPU, 内存容量大小直接决定了电脑的反应快慢, 所以很多朋友给电脑升级的时候都会优先考虑内存条升级. 大家看 ...

最新文章

  1. 《深入理解Java虚拟机》-----第3章 垃圾收集器与内存分配策略
  2. C#的四种Timer介绍
  3. 【redis】在windos下的redis服务器的搭建
  4. 用busybox制作并配置根文件系统
  5. ROS(kinetic)安装中的一些问题(已解决)
  6. [转载] R语言read.table函数
  7. MFC文件的读写操作,类的序列化与反序列化,CFile,CFileDialog,CArchive,CStdioFile
  8. C6000 DSP技术深度探索(1)---关于启动方式
  9. 联想台式计算机 恢复出厂设置,lenovo电脑如何恢复出厂设置_lenovo台式电脑恢复出厂设置操作方法-win7之家...
  10. 多行文字内容溢出显示点点点(...)省略号
  11. 英读廊——一个人的旅行:原汁原味希腊克里特游记
  12. 【FPGA】四、按键消抖
  13. 干货 | 超全整理|Python 操作 Excel 库 xlwings 常用操作详解!
  14. Coredump:core与kernel的区别,以及coredump具体指什么?
  15. qcustomplot时间坐标轴画直线_QCustomplot使用分享(六) 坐标轴和网格线
  16. Rootkit技术基础(4)
  17. 深信服面试常见算法题整理笔记
  18. 按键按动次数计数c语言,二、Windows按键消息—重复计数、OEM扫描码、扩充键旗标、内容代...
  19. inter酷睿后缀含义
  20. hive报错整理之Malformed ORC file 、Invalid postscript.

热门文章

  1. Windows vs Linux:\r\n 与 \r
  2. 我们怎样确保从大数据计算中获得价值
  3. 《大道至简》第一章伪代码
  4. GCPC2014 C Bounty Hunter
  5. 剑指Offer - 九度1367 - 二叉搜索树的后序遍历序列
  6. 将pcre、zlib等包编译进nginx里去(转)
  7. SQL Server : 禁止在SQL Server中生成用户实例
  8. 《看完它面试必solo | 寻找C站宝藏》
  9. 部署项目的问题(三)—— node启动服务时listen监听的端口被占用
  10. 实战Vue简易项目(2)定制开发环境