题面
在Byteland 一共有n 座城市,编号依次为1 到n,这些城市之间通过m 条单向公路连接。
对于两座不同的城市a 和b,如果a 能通过这些单向道路直接或间接到达b,且b 也能如此到达a,那么它们就会被认为是一对友好城市。
Byteland 的交通系统十分特殊,第i 天只有编号在[li, ri] 的单向公路允许通行,请写一个程序,计算每天友好城市的对数。
注意:(a, b) 与(b, a) 没有区别。
70
Kosarajo算法
这是一个区别于tarjan算法的求强连通分量的算法。
流程
1.在逆图上进行一次dfs,然后记录下每个点的后序编号(?)。
e.g.
void dfs(int v){
dfs(next(v)); //先往后继递归
st[++st[0]]=v; //再在这记录后序编号
}
2.按后序编号从大到小在原图上再进行一次dfs,所能走到的就是与这个点处于同一强连通分量的点。
3.时间复杂度为\(O(n+m)\)
正文
我们看到给出的区间的左端点和右端点都是不减的,就有边只会进出一次。
所以我们可以用邻接矩阵维护边,然后就可以使用Kosarajo算法统计答案。
这样的时间复杂度为\(O(n^2*q)\),然而这还是过不了70分。
bitset优化
由于边不存在权值,所以我们用bitset来存储邻接矩阵。
然后Kosarajo算法统计答案时,也要用到bitset的位运算优化。
于是就能把复杂度优化到\(O(\frac{1}{32}n^2*q)\);
可能会用到的bitset函数
.reset(),归零;
._Find_next(int v),查找第v为后的第一个1,返回位置。
Warning:bitset的下标是从0开始算,所以如果要从头开始找,就用._Find_next(-1)。
100
100分与70分的区别就是,边可能会重复加入。
注意到,如果对于两个已有的边集(邻接矩阵),那么我们可以利用bitset来优化合并,达到\(O(\frac{n^2}{32})\)的复杂度,是很优秀的。
我们给\(m\)条边分块,共\(\sqrt m\)块,每个块考虑使用bitset来存储邻接矩阵;
按照一般的分块套路,我们确实可以用\(O(q*(\sqrt m*\frac{n^2}{32}+\sqrt m))\)来维护邻接矩阵。
但是仍然无法被题目苛刻的条件所接受。
于是我们考虑对块建立ST表,那么就能把维护的时间降到\(O(q*(log_{\sqrt m}*\frac{n^2}{32}+\sqrt m))\)。
就能通过本题。
为什么不用tarjan,而用Kosarajo代替
对于tarjan而言,他需要遍历一些已经被访问的点,所以不能使用bitset优化;
而Kosarajo,每个点只会被遍历一次,所以能使用bitset优化。
为什么不用线段树,而用ST表和分块代替
线段树的空间不能被接受,是\(O(m*log_m*\frac{n^2}{32})\)。
Code
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<bitset>
#define ll long long
#define fo(i,x,y) for(int i=x;i<=y;i++)
#define fd(i,x,y) for(int i=x;i>=y;i--)
using namespace std;
const char* fin="friend.in";
const char* fout="friend.out";
const int inf=0x7fffffff;
const int maxn=157,maxm=300007,maxk=557,maxl=10;
int n,m,q,a[maxm][2],ks,num,st[maxn],cnt=0,pre[maxn],ans;
bitset<maxn> b[maxk][maxl][maxn],bb[maxk][maxl][maxn],bz,p[maxn],pp[maxn];
void make(int l,int r){
int k=maxl-1;
fo(i,1,n) p[i].reset(),pp[i].reset();
while (l<=r){
if (l+(1<<k)-1<=r){
fo(i,1,n) p[i]|=b[l][k][i],pp[i]|=bb[l][k][i];
l+=(1<<k);
}
if (k>0) k--;
}
}
void dfs(int v){
bz.reset(v);
while (1){
int k=(pp[v]&bz)._Find_next(0);
if (k>n) break;
dfs(k);
}
st[++st[0]]=v;
}
void Dfs(int v){
cnt++;
bz.reset(v);
while (1){
int k=(p[v]&bz)._Find_next(0);
if (k>n) break;
Dfs(k);
}
}
void kosarajo(){
ans=0;
bz.set();
st[0]=0;
fo(i,1,n)
if (bz[i]){
dfs(i);
}
bz.set();
fd(i,st[0],1){
if (bz[st[i]]){
cnt=0;
Dfs(st[i]);
ans+=cnt*(cnt-1)/2;
}
}
}
int main(){
freopen(fin,"r",stdin);
freopen(fout,"w",stdout);
scanf("%d%d%d",&n,&m,&q);
fo(i,1,m) scanf("%d%d",&a[i][0],&a[i][1]);
ks=int(sqrt(m));
int j=1,k=ks;
fo(i,1,m){
if (i>k){
k+=ks;
j++;
}
b[j][0][a[i][0]].set(a[i][1]);
bb[j][0][a[i][1]].set(a[i][0]);
}
num=j;
fd(i,num,1){
fo(j,1,maxl-1){
if (i+(1<<(j-1))>num) break;
fo(k,1,n){
b[i][j][k]=b[i][j-1][k]|b[i+(1<<(j-1))][j-1][k];
bb[i][j][k]=bb[i][j-1][k]|bb[i+(1<<(j-1))][j-1][k];
}
}
}
fo(i,1,q){
int l,r;
scanf("%d%d",&l,&r);
int tmp=(l-1)/ks+1,tmd=(r-1)/ks+1;
make(tmp+1,tmd-1);
if (tmp!=tmd){
fo(j,l,tmp*ks) p[a[j][0]].set(a[j][1]),pp[a[j][1]].set(a[j][0]);
fo(j,(tmd-1)*ks+1,r) p[a[j][0]].set(a[j][1]),pp[a[j][1]].set(a[j][0]);
}else fo(j,l,r) p[a[j][0]].set(a[j][1]),pp[a[j][1]].set(a[j][0]);
/*fo(i,1,n) cout<<p[i]<<endl;
fo(i,1,n) cout<<pp[i]<<endl;*/
kosarajo();
printf("%d\n",ans);
}
return 0;
}
【JZOJ5064】【GDOI2017第二轮模拟day2】友好城市 Kosarajo算法+bitset+ST表+分块的更多相关文章
-
GDOI2017第二轮模拟day1 总结
平民比赛 这场比赛的暴力分非常友好. 但是我并没有拿到全部的暴力分. 1(暴力分\(60/100\)) 暂时我可以拿的暴力分为\(30/100\),直接mst模拟即可. 然而当时打了个辣鸡莫队,结果爆 ...
-
【JZOJ5060】【GDOI2017第二轮模拟day1】公路建设 线段树+最小生成树
题面 在Byteland一共有n 个城市,编号依次为1 到n,它们之间计划修建m条双向道路,其中修建第i 条道路的费用为ci. Byteasar作为Byteland 公路建设项目的总工程师,他决定选定 ...
-
[jzoj5073 GDOI2017第二轮模拟] 影魔
Description 影魔,奈文摩尔,据说有着一个诗人的灵魂.事实上,他吞噬的诗人灵魂早已成千上万.千百年来,他收集了各式各样的灵魂,包括诗人.牧师.帝王.乞丐.奴隶.罪人,当然,还有英雄.每一个灵 ...
-
【JZOJ5088】【GDOI2017第四轮模拟day2】最小边权和 排序+动态规划
题面 有一张n个点m条边的有向图,每条边有一个互不相同的边权w,有q个询问,要求你从点a经过不超过c条边到点b,要求经过的边权递增并和尽量小,求出最小的边权和,如果没有合法方案则输出-1. 对于100 ...
-
【JZOJ5071】【GDSOI2017第二轮模拟】奶酪 树形dp
题面 CJY很喜欢吃奶酪,于是YJC弄到了一些奶酪,现在YJC决定和CJY分享奶酪. YJC弄到了n-1块奶酪,于是他把奶酪挂在了一棵n个结点的树上,每根树枝上挂一块奶酪,每块奶酪都有重量. YJC和 ...
-
【JZOJ5068】【GDSOI2017第二轮模拟】树 动态规划+prufer序列
题面 有n个点,它们从1到n进行标号,第i个点的限制为度数不能超过A[i]. 现在对于每个s (1 <= s <= n),问从这n个点中选出一些点组成大小为s的有标号无根树的方案数. 10 ...
-
【Noip模拟 20161005】友好城市
问题描述 小ww生活在美丽的ZZ国.ZZ国是一个有nn个城市的大国,城市之间有mm条单向公路(连 接城市ii.jj的公路只能从ii连到jj).城市ii.jj是友好城市当且仅当从城市ii能到达城市jj并 ...
-
DFRobot万物互联大赛第二轮
前言 最近放在阳台的花草被啥东西给吃了,然后厨房挂在墙上的小虾米也不知道咋的被抓破吃光了(我怀疑是隔隔壁两条泰迪),所以打算做个简单的项目,教训一下偷吃贼.时间比较仓促,内容比较多,能力有比较有限,好 ...
-
【百度之星2014~初赛(第二轮)解题报告】Chess
声明 笔者近期意外的发现 笔者的个人站点http://tiankonguse.com/ 的非常多文章被其他站点转载.可是转载时未声明文章来源或參考自 http://tiankonguse.com/ 站 ...
随机推荐
-
ionic ios iframe 白屏
之前碰到一个问题: 在ios下边使用iframe出现白屏问题 android下边正常 原因是ios对app打开外部网页有限制需要取消限制 解决方法 1.确认添加whitelist 插件 2.在conf ...
-
Linux系统下Nginx安装详解
该随笔为个人原创,后期会根据项目实践实时更新,如若转载,请注明出处,方便大家获得最新博文! 注:安装Nginx需要Linux系统已经安装 openssl-fips-2.0.2.tar.gz zli ...
-
Java 网络编程(一)
网络通讯要素 IP地址(InetAddress) 端口号 传输协议 图示: TDP/IP模型 以OSI 7层模型讲解数据的传输 InetAddress InetAddress类主要表示IP地址. ...
-
《JAVA核心技术卷 卷1 基础知识》
第一卷 关键字:体系结构中立,可移植性,高性能,多线程 体系机构中立:通过解释字节码实现,优点是,让JAVA能在很多机器上运行.缺点是运行速度很慢. 可移植性:因为JAVA的基本数据类型有固定的大小. ...
-
C#中的switch case
在C#中switch(type){case tpye1:break;case tpye2:break;case tpye3:break;case tpye4:break;};其中type可以是数字,也 ...
-
树上莫队 wowow
构建:像线性的莫队那样,依旧是按sqrt(n)为一块分块. int dfs(int x){ ; dfn[x]=++ind; ;i<=;i++) if (bin[i]<=deep[x]) f ...
-
1.Tsung介绍(翻译)
1.介绍 1.1什么是Tsung? Tsung(以前是IDX-Tsunami)是一种分布式负载测试工具.它是基于协议的,并且通常被用于压测HTTP, WebDAV, SOAP, PostgreSQL, ...
-
树莓派3代刷ubuntu mate在命令行下配置wifi不能连接的一个诡异的bug的解决
家里路由器不在自己卧室,用树莓派考虑用wifi,之前用Raspberry官方系统,按照教程写的wpa.conf可以连接wifi,后来重新刷ubuntu mate 16.04就不好用了 各种找原因,后来 ...
-
easyui datagrid 后台返回所有数据,前台分页
function pagerFilter(data) { if (typeof data.length == 'number' && typeof data.splice == 'fu ...
-
webuploader在ie9以下失效原因
在项目中为了兼容ie9,使用webuploader插件,发现在部分电脑的ie9模式下点击无响应,排查原因,最终发现是不是插件有问题,而是ie浏览器没有flash的加载项,最终下载flash,并安装运行 ...