洛谷 1710
来源:互联网 发布:教父刀数据 编辑:程序博客网 时间:2024/05/19 03:25
这道题是一道图论题,题目的意思是每次删除一条边,询问当前有多少点与1号节点的最短路的值与未删边之前不同。首先我们一定是求出原图的最短路,由于我们可以默认边权是1,于是我们可以BFS,这样我们就能够得到一张“最短路图”,所谓最短路图就是说对于一条边(u,v),我们只走dis[v]=dis[u]+1的边,这样如果删除的边不是最短路图上的边,对其他点是没有任何影响的,那我们考虑如果删除最短路图上的边,只要这条边的端点还在最短路图中能被1号点访问到,那么它的最短路一定不会变化,那我们怎么维护呢,感觉正着做很不好搞,因为删除一条边后,即使它的两端点不与1连通,它的两端点的点也可能与1连通,我们考虑正难则反,离线处理,将删边变成加边,维护一个bz数组表示每个点是否已经和1连通,这样,每加进一条边,我们判断它能否将1与边的出点连通,如果连通,我们就从这条边的出点DFS,将所有bz[i]=0的点变成1,对于每个bz[i]=1的点,我们不再进行DFS,这样就保证了每个点只被访问1次,也就保证了复杂度是线性的。
#include<cstdio>#include<cstring>#include<algorithm>using namespace std;#define maxn 400005int n,m,q,l=1,w=0;int pre[maxn],other[maxn],last[maxn];int pre1[maxn],other1[maxn],last1[maxn];int dis[maxn],que[maxn],ans[maxn],query[maxn],cnt;bool vis[maxn],flag[maxn],pd[maxn],bj[maxn];struct edge{ int fr,to; }e[maxn];int read(void){ char ch=getchar(); int x=0; while (ch<'0'||ch>'9') ch=getchar(); while (ch>='0'&&ch<='9') { x=x*10+ch-'0'; ch=getchar(); } return x;}void connect(int x,int y){ l++; pre[l]=last[x]; last[x]=l; other[l]=y; }void connect1(int x,int y){ w++; pre1[w]=last1[x]; last1[x]=w; other1[w]=y;}void pre_bfs(void) { int h=1,t=1; vis[1]=1;que[1]=1; while (h<=t) { int u=que[h];h++; for (int p=last[u];p;p=pre[p]) { int v=other[p]; if (vis[v]) continue; dis[v]=dis[u]+1; que[++t]=v; vis[v]=1; } }}void bfs(void){ memset(vis,0,sizeof vis); vis[1]=1;que[1]=1; int h=1,t=1; while (h<=t) { int u=que[h];h++; for (int p=last[u];p;p=pre[p]) { int v=other[p]; if (dis[v]==dis[u]+1) flag[p/2]=1; if (vis[v]) continue; que[++t]=v; vis[v]=1; } }}void dfs(int u){ cnt++;bj[u]=1; for (int p=last1[u];p;p=pre1[p]) { int v=other1[p]; if (bj[v]) continue; dfs(v); }}int main(){ //scanf("%d%d%d",&n,&m,&q); n=read();m=read();q=read(); for (int i=1;i<=m;i++) { int a,b; //scanf("%d%d",&a,&b); a=read();b=read(); e[i].fr=a;e[i].to=b; connect(a,b);connect(b,a); } pre_bfs(); bfs(); for (int i=1;i<=q;i++) { int a; //scanf("%d",&a); a=read(); pd[a]=1;query[i]=a; } for (int i=1;i<=m;i++) if (dis[e[i].fr]>dis[e[i].to]) swap(e[i].fr,e[i].to); bj[1]=1;cnt=1; for (int i=1;i<=m;i++) if (!pd[i]&&flag[i]) { if (bj[e[i].fr]&&bj[e[i].to]) continue; connect1(e[i].fr,e[i].to); if (bj[e[i].fr]) dfs(e[i].to); } ans[q]=n-cnt; for (int i=q-1;i>=1;i--) { int num=query[i+1]; if ((!(bj[e[num].fr]&&bj[e[num].to]))&&flag[num]) connect1(e[num].fr,e[num].to); if (bj[e[num].fr]&&flag[num]&&!bj[e[num].to]) dfs(e[num].to); ans[i]=n-cnt; } for (int i=1;i<=q;i++) printf("%d\n",ans[i]); return 0; }
0 0
- 洛谷 1710
- 洛谷1710 地铁涨价
- 1710
- Codevs 1710 == POJ 1190 生日蛋糕 == 洛谷P1731
- HDOJ 1710
- HDU 1710
- ZOJ 1710 The Snail
- ZOJ 1710 The Snail
- 1710: 最后一个1
- ZJNU 1710 dfs
- HDU 1710 已知前序中序须求后序。
- HDU 1710 二叉树水题
- ZCMU—1710
- CodeVS 1710 生日蛋糕 题解
- codevs 1710 生日蛋糕
- 1710--1804书单
- DevExperience(1710)
- 洛谷
- 枚举
- 《C语言点滴》- 总结
- 欢迎使用CSDN-markdown编辑器
- JVM其实并不难
- Xcode发布测试版本,直接通过Safari在线安装ipa
- 洛谷 1710
- Codevs 2188 最长上升子序列 dp
- HDU 4417 Super Mario(线段树)
- 写不了编程,我就写日记。
- POJ3281Dinicing(网络流初步)
- javascript笔记(六)(Date)
- 数据结构示例之圆形队列模拟舞会
- phphub5 centos 安装
- iOS - iOS10 添加本地推送(Local Notification)