$f(i,G)_{x}$为$x$对$i$是否有贡献,即在枚举到$x$时,$i$与$x$是否强连通

事实上,$f(i,G)_{x}=1$即不经过$[1,x)$中的点且$i$与$x$强连通

首先,当存在这样的路径,即使$[1,x)$中的点全部删除两者也仍然强连通(有贡献)

同时,若不存在这样的路径,考虑任意两条$i$到$x$和$x$到$i$的路径$P_{1}$和$P_{2}$,对于$P_{1}$和$P_{2}$中编号最小的点$y$,即证明若$y<x$,则其在枚举到$x$时必然被删去

不妨假设$y$在$P_{1}$中,当枚举到$y$时显然存在走$P_{1}$从$i$到$y$的路径,以及$y$到$i$的路径(先走$P_{1}$从$y$到$i$,再走$P_{2}$从$x$到$i$),那么$y$即会被删除

综上,也就证明了前面的结论

考虑对于确定的$i$和$x$,满足$f(i,G_{j})_{x}=1$的$j$必然是一个前缀,下面求出这个前缀——

令$d(i,x,y)$表示从$i$到$x$不经过$[1,y]$的所有路径中,经过的编号最小值的最大值,那么这个前缀的范围即$[0,\min(d(i,x,x-1),d(x,i,x-1)))$,差分统计即可

(特别的,为了方便,定义$d(i,i,x)$为$m+1$)

下面考虑如何求出$d(i,x,y)$,显然其与最短路类似,且定义又与Floyd的过程相同,即从大到小枚举中转点来转移即可,复杂度为$o(n^{3}+m)$

也可以暴力计算,即枚举$x$并删去这些点,以$x$为起点对原图和反图分别求一次,同样可以用dijkstra等最短路算法,即可做到$o(nm\log n)$的复杂度

上述两种算法复杂度并不正确,但常数优秀都可以通过

下面给出两份被卡常数的代码,分别是44(Floyd)和80(Dijkstra)

  1. 1 #include<bits/stdc++.h>
  2. 2 using namespace std;
  3. 3 #define N 1005
  4. 4 #define M 300005
  5. 5 int n,m,x,y,tot[M],f[N][N];
  6. 6 int main(){
  7. 7 scanf("%d%d",&n,&m);
  8. 8 memset(f,-1,sizeof(f));
  9. 9 for(int i=1;i<=n;i++)f[i][i]=m+1;
  10. 10 for(int i=1;i<=m;i++){
  11. 11 scanf("%d%d",&x,&y);
  12. 12 f[x][y]=i;
  13. 13 }
  14. 14 for(int i=n;i;i--){
  15. 15 for(int j=1;j<=n;j++)
  16. 16 for(int k=1;k<=n;k++)
  17. 17 if ((f[j][i]>0)&&(f[i][k]>0))f[j][k]=max(f[j][k],min(f[j][i],f[i][k]));
  18. 18 for(int j=i;j<=n;j++)
  19. 19 if ((f[i][j]>0)&&(f[j][i]>0))tot[min(f[i][j],f[j][i])-1]++;
  20. 20 }
  21. 21 for(int i=m;i;i--)tot[i-1]+=tot[i];
  22. 22 for(int i=0;i<=m;i++)printf("%d ",tot[i]);
  23. 23 }

  1. 1 #include<bits/stdc++.h>
  2. 2 using namespace std;
  3. 3 #define N 1005
  4. 4 #define M 200005
  5. 5 struct Edge{
  6. 6 int nex,to,len;
  7. 7 }edge[M<<1];
  8. 8 priority_queue<pair<int,int> >q;
  9. 9 int E,n,m,x,y,head[2][N],d[2][N],vis[N],tot[M];
  10. 10 void add(int p,int x,int y,int z){
  11. 11 edge[E].nex=head[p][x];
  12. 12 edge[E].to=y;
  13. 13 edge[E].len=z;
  14. 14 head[p][x]=E++;
  15. 15 }
  16. 16 void calc(int p,int st){
  17. 17 memset(d[p],-1,sizeof(d[p]));
  18. 18 memset(vis,0,sizeof(vis));
  19. 19 d[p][st]=m+1;
  20. 20 q.push(make_pair(d[p][st],st));
  21. 21 while (!q.empty()){
  22. 22 int k=q.top().second;
  23. 23 q.pop();
  24. 24 if (vis[k])continue;
  25. 25 vis[k]=1;
  26. 26 for(int i=head[p][k];i!=-1;i=edge[i].nex)
  27. 27 if ((edge[i].to>=st)&&(d[p][edge[i].to]<min(d[p][k],edge[i].len))){
  28. 28 d[p][edge[i].to]=min(d[p][k],edge[i].len);
  29. 29 q.push(make_pair(d[p][edge[i].to],edge[i].to));
  30. 30 }
  31. 31 }
  32. 32 }
  33. 33 int main(){
  34. 34 scanf("%d%d",&n,&m);
  35. 35 memset(head,-1,sizeof(head));
  36. 36 for(int i=1;i<=m;i++){
  37. 37 scanf("%d%d",&x,&y);
  38. 38 add(0,x,y,i);
  39. 39 add(1,y,x,i);
  40. 40 }
  41. 41 for(int i=1;i<=n;i++){
  42. 42 calc(0,i),calc(1,i);
  43. 43 for(int j=i;j<=n;j++)
  44. 44 if ((d[0][j]>0)&&(d[1][j]>0))tot[min(d[0][j],d[1][j])-1]++;
  45. 45 }
  46. 46 for(int i=m;i;i--)tot[i-1]+=tot[i];
  47. 47 for(int i=0;i<=m;i++)printf("%d ",tot[i]);
  48. 48 }

事实上,还可以做到更优秀的复杂度,回到最初的结论

考虑先枚举$x$,并倒序加边,之后维护有多少个点$i$与$x$强连通即可

强连通即分为两部分,即$x$能到达$i$与$i$能到达$x$,且对于每一个具有单调性,即至多修改一次,因此只需要每一次能够快速找到修改的点即可(以下先考虑前者)

假设加入边$(a,b)$,若$a<x$或$b<x$显然无意义,否则分类讨论:

1.若$x$不能到达$a$或$x$能到达$b$,即目前不影响答案,但其会在以后影响答案,即加入边集

2.若$x$能到达$a$但不能到达$b$,从$b$开始dfs搜索,且在经过一条边后删除其

(关于这一做法的正确性:当一条边被经过后,若其内部没有加边显然没有再搜索的意义,而加边不妨直接对其子树内部搜索即可)

对于$i$能否到达$x$,对其反图做同样的过程即可

此时,对于每一条边仅被搜索一次,复杂度即为$o(nm)$,可以通过

另外由于常数问题,建议使用bfs,且这份代码也只能在洛谷上通过(常数问题)

  1. 1 #include<bits/stdc++.h>
  2. 2 using namespace std;
  3. 3 #define N 1005
  4. 4 #define M 200005
  5. 5 struct Edge{
  6. 6 int nex,to,len;
  7. 7 }edge[M<<1];
  8. 8 priority_queue<pair<int,int> >q;
  9. 9 int E,n,m,x,y,head[2][N],d[2][N],vis[N],tot[M];
  10. 10 void add(int p,int x,int y,int z){
  11. 11 edge[E].nex=head[p][x];
  12. 12 edge[E].to=y;
  13. 13 edge[E].len=z;
  14. 14 head[p][x]=E++;
  15. 15 }
  16. 16 void calc(int p,int st){
  17. 17 memset(d[p],-1,sizeof(d[p]));
  18. 18 memset(vis,0,sizeof(vis));
  19. 19 d[p][st]=m+1;
  20. 20 q.push(make_pair(d[p][st],st));
  21. 21 while (!q.empty()){
  22. 22 int k=q.top().second;
  23. 23 q.pop();
  24. 24 if (vis[k])continue;
  25. 25 vis[k]=1;
  26. 26 for(int i=head[p][k];i!=-1;i=edge[i].nex)
  27. 27 if ((edge[i].to>=st)&&(d[p][edge[i].to]<min(d[p][k],edge[i].len))){
  28. 28 d[p][edge[i].to]=min(d[p][k],edge[i].len);
  29. 29 q.push(make_pair(d[p][edge[i].to],edge[i].to));
  30. 30 }
  31. 31 }
  32. 32 }
  33. 33 int main(){
  34. 34 scanf("%d%d",&n,&m);
  35. 35 memset(head,-1,sizeof(head));
  36. 36 for(int i=1;i<=m;i++){
  37. 37 scanf("%d%d",&x,&y);
  38. 38 add(0,x,y,i);
  39. 39 add(1,y,x,i);
  40. 40 }
  41. 41 for(int i=1;i<=n;i++){
  42. 42 calc(0,i),calc(1,i);
  43. 43 for(int j=i;j<=n;j++)
  44. 44 if ((d[0][j]>0)&&(d[1][j]>0))tot[min(d[0][j],d[1][j])-1]++;
  45. 45 }
  46. 46 for(int i=m;i;i--)tot[i-1]+=tot[i];
  47. 47 for(int i=0;i<=m;i++)printf("%d ",tot[i]);
  48. 48 }

[loj3501]图函数的更多相关文章

  1. matlab读图函数

    最基本的读图函数:imread imread函数的语法并不难,I=imread('D:\fyc-00_1-005.png');其中括号内写图片所在的完整路径(注意路径要用单引号括起来).I代表这个图片 ...

  2. JavaScript思维导图—函数基础

    JavaScript思维导图-来自@王子墨http://julying.com/blog/the-features-of-javascript-language-summary-maps/

  3. Django--视图函数views

    1 视图函数 一个视图函数,简称视图,是一个简单的Python 函数,它接受Web请求并且返回Web响应.响应可以是一张网页的HTML内容,一个重定向,一个404错误,一个XML文档,或者一张图片. ...

  4. django3-视图函数进阶

    1.视图函数的分类 FBV(fucntion base view) CBV(class base view) ,CBV根据定义的方法名 ,判断什么请求执行什么函数 2.FBV转换CBV (不太对劲) ...

  5. Django--视图函数

    目录 视图函数 HttpRequest对象 request属性 request常用方法 HttpResponse对象 render() redirect() JsonResponse 视图函数 一个视 ...

  6. Django-05-视图函数

    http请求中产生两个核心对象: http请求:HttpRequest对象 http响应:HttpResponse对象 所在位置:django.http 之前我们用到的参数request就是HttpR ...

  7. Django-视图函数view

    目录 1.Django的视图函数view 1.1一个简单的视图 2.CBV和FBV 3.使用Mixin(了解) 4.给视图加装饰器 4.1使用装饰器装饰FBV 4.2使用装饰器装饰CBV 5.requ ...

  8. Django-视图函数/模板渲染/过滤器

    一.Django的视图函数 一个视图函数(类),简称视图,是一个简单的Python 函数(类),它接受Web请求并且返回Web响应. 响应可以是一张网页的HTML内容,一个重定向,一个404错误,一个 ...

  9. MATLAB 颜色图函数(imagesc/scatter/polarPcolor/pcolor)

    2维的热度图 imagesc imagesc(x, y, z),x和y分别是横纵坐标,z为值,表示颜色 imagesc(theta,phi,slc); colorbar xlabel(); ylabe ...

随机推荐

  1. Serverless 的价值

    作者 | 许晓斌 阿里云高级技术专家 本文整理自<Serverless 技术公开课>,关注"Serverless"公众号,回复 入门 ,即可获取 Serverless ...

  2. Android QMUI实战:沉浸式/适配状态栏

    近期研究QMUI换肤的实现,顺便分析了下QMUI的沉浸式. 网上已有很多关于QMUI实现页面沉浸式的文章,简而言之:复杂了. 本期,我们仅通过几行代码,即可完美实现页面沉浸式效果,并轻松匹配换肤的色彩 ...

  3. Kubernetes Job Controller 原理和源码分析(一)

    概述什么是 JobJob 入门示例Job 的 specPod Template并发问题其他属性 概述 Job 是主要的 Kubernetes 原生 Workload 资源之一,是在 Kubernete ...

  4. DL4J实战之六:图形化展示训练过程

    欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 本篇概览 本篇是<DL4J实战>系列的第六 ...

  5. 2.1 OOP & SOLID

    OOP & SOLID Implementing DDD highly relies on the Object Oriented Programming (OOP) and SOLID pr ...

  6. (课内)信安数基RSA-基础&&解密加速

    RSA基本实现 首先获得N比特的伪随机数:使用Random库中内容. randint(n,m) 表示生成一个在n和m之间的随机数, **表示乘幂. getPrime找素数,or 1运算是一种优化:如果 ...

  7. 【UE4 C++ 基础知识】<8> Delegate 委托

    概念 定义 UE4中的delegate(委托)常用于解耦不同对象之间的关联:委托的触发者不与监听者有直接关联,两者通过委托对象间接地建立联系. 监听者通过将响应函数绑定到委托上,使得委托触发时立即收到 ...

  8. 安装多个版本的MySQL

    安装多个版本的MySQL 之前在PC机上安装了 MySQL 5.5 后续发现了窗口函数,而窗口函数是 MySQL8 以后才支持的,故在本地又安装了一个 MySQL 8 安装MySQL 5.5 进入my ...

  9. Beta阶段第四次会议

    Beta阶段第四次会议 时间:2020.5.20 完成工作 姓名 工作 难度 完成度 ltx 1.对小程序进行修改2.提出相关api修改要求 轻 85% xyq 1.设计所需api文档2.编写相关技术 ...

  10. 用Python去除PDF水印

    今天介绍下用 Python 去除 PDF (图片)的水印.思路很简单,代码也很简洁. 首先来考虑 Python 如何去除图片的水印,然后再将思路复用到 PDF 上面. 这张图片是前几天整理<数据 ...