LOJ bitset+分块 大内存毒瘤题
题面
$ 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 $ 的复杂度完成,但是只涉及能否我们可以用二进制。
- 仔细分析求得答案需要什么关键信息
- 对于一连串操作可以一次完成,就考虑分治或分块
- 对于两种操作会互相影响,考虑先预处理一种操作在进行第二种操作
- 二进制和是与否,这个对于复杂度优化很好用。
- $ 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 int
using 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;
}
LOJ bitset+分块 大内存毒瘤题的更多相关文章
- 【卡常 bitset 分块】loj#6499. 「雅礼集训 2018 Day2」颜色
好不容易算着块大小,裸的分块才能过随机极限数据:然而这题在线的数据都竟然是构造的…… 题目描述 有 $n$ 个数字,第 $i$ 个数字为 $a_i$. 有 $m$ 次询问,每次给出 $k_i$ 个区间 ...
- [LOJ#114]k 大异或和
[LOJ#114]k 大异或和 试题描述 这是一道模板题. 给由 n 个数组成的一个可重集 S,每次给定一个数 k,求一个集合 T⊆S,使得集合 T 在 S 的所有非空子集的不同的异或和中,其异或和 ...
- PHP读写大“二进制”文件,不必申请很大内存(fopen、fread、fwrite、fclose)
<?php /** * 读写大二进制文件,不必申请很大内存 * 只有读取到内容才创建文件 * 保证目录可写 * * @param string $srcPath 源文件路径 * @param s ...
- 一个Java对象到底占用多大内存?
最近在读<深入理解Java虚拟机>,对Java对象的内存布局有了进一步的认识,于是脑子里自然而然就有一个很普通的问题,就是一个Java对象到底占用多大内存? 在网上搜到了一篇博客讲的非常好 ...
- JVM优化之调整大内存分页(LargePage)
转自:http://cjjwzs.iteye.com/blog/1059381 本文将从内存分页的原理,如何调整分页大小两节内容,向你阐述LargePage对JVM的性能有何提升作用,并在文末点明了大 ...
- (转)mongoDB 禁用大内存页面 transparent_hugepage=never
最近在学mongoDB,安装倒没什么困难,有yum仓库.不过接入ctl后的一条warning倒挺让人烦心的. 1 2 2015-03-22T09:27:00.222+0800 I CONTROL [ ...
- 一个Java对象到底占用多大内存
在网上搜到了一篇博客讲的非常好,里面提供的这个类也非常实用: import java.lang.instrument.Instrumentation; import java.lang.reflect ...
- mysql大内存高性能优化方案
mysql优化是一个相对来说比较重要的事情了,特别像对mysql读写比较多的网站就显得非常重要了,下面我们来介绍mysql大内存高性能优化方案 8G内存下MySQL的优化 按照下面的设置试试看:key ...
- Android 开发绕不过的坑:你的 Bitmap 究竟占多大内存?
0.写在前面 本文涉及到屏幕密度的讨论,这里先要搞清楚 DisplayMetrics 的两个变量,摘录官方文档的解释: density:The logical density of the displ ...
随机推荐
- easyhook源码分析三——申请钩子
EasyHook 中申请钩子的原理介绍 函数原型 内部使用的函数,为给定的入口函数申请一个hook结构. 准备将目标函数的所有调用重定向到目标函数,但是尚未实施hook. EASYHOOK_NT_IN ...
- idea中git回退本地仓库版本
场景:代码commit到本地仓库,还没有push到远程仓库,这时要回退代码. 介绍下Reset Head中三种Reset Type类型: 1.Mixed(默认):它回退到某个版本,本地会保留源码,回退 ...
- 利用Git版本控制管理你的项目
准备工作 项目创建完成后,将项目版本控制起来,今后每个版本的迭代会非常清楚,同时也有助于项目进行协同开发. 还有一个十分重要的问题是:项目上线后,线上的运行的程序的配置与线下进行测试的配置文件是不一样 ...
- 【2】通过Ajax方式上传文件(图片),使用FormData进行Ajax请求
HTML: <form id= "uploadForm"> <p >指定文件名: <input type="text" name= ...
- Stream的并行计算
一.Stream并行计算体验,利用多核加快计算速度 stream的并发,多个cpu执行同一个任务,提高效率: 需求:从1+...+10000000,看下各种计算方法的运行时间是多少 代码例子如下: p ...
- centos官网镜像下载方法
1.CentoS简介 CentOS(Community Enterprise Operating System,社区企业操作系统)是一个基于Red Hat Linux 提供的可自由使用源代码的企业级L ...
- c# 排列组合代码类
/// <summary> /// 排列组件算法类 /// </summary> /// <typeparam name="T"></ty ...
- Django中的自定义过滤器
一.为什么要自定义Django中的自定义过滤器:Django中提供了很多内置的过滤器和标签,详见链接django官网,主要有以下几个: autoescape(自动转义)block(模板继承)csrf_ ...
- (转载)深入解析String#intern
本文转载自:深入解析String#intern 引言 在 JAVA 语言中有8中基本类型和一种比较特殊的类型String.这些类型为了使他们在运行过程中速度更快,更节省内存,都提供了一种常量池的概念. ...
- Java IO NIO详细讲解
1.IO Java IO概述 2.NIO Java NIO浅析