CF757F Team Rocket Rises Again

全体起立,全体起立,这是我A的第一道黑题(虽然是CF的);

来一波番茄攻击;

不扯淡了,这道题也是学习支配树(之前)应该做的题;

灾难不同的是,那个是直接给你有向图,这里给的是无向图;

我们要求的是删除一个点会造成多少点的最短路发生变化,那么我们可以根据最短路再建一个有向图,这样就和灾难一样了;

很不幸,我建了四个图;

因为一开始写挂了所以图的编号是乱的;(这并不影响我AC)
add是无向图,add2是有向图,add4是反图,add3是建出来的支配树;

首先我们为什么要建反图:

{

一个点是否对其他的点有价值,就是看是否他在最短路径上;

我们根据有向图算出了拓扑序,拓扑序靠前的就是靠近起始点的;

我们需要建支配树,那么当前点要当谁的儿子?

当然是所有连向他的点的LCA,因为所有连向他的点删掉后(点数大于等于2)还可以在其他的点上走;

我们当初只建了一个有向图连向当前点,我们还要回去找LCA,所以要建一个反图;
}

然后子树大小即为答案;(取最大值)

#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=3e5+;
int n,m,s;
int pre[maxn*],last[maxn],other[maxn*],l;
ll len[maxn*];
int pre2[maxn*],last2[maxn],other2[maxn*],l2;
int pre3[maxn*],last3[maxn],other3[maxn*],l3;
int pre4[maxn*],last4[maxn],other4[maxn*],l4;
void add(int x,int y,ll z)
{
l++;
pre[l]=last[x];
last[x]=l;
other[l]=y;
len[l]=z;
}
void add2(int x,int y)
{
l2++;
pre2[l2]=last2[x];
last2[x]=l2;
other2[l2]=y;
//len[l]=z;
} void add3(int x,int y)
{
l3++;
pre3[l3]=last3[x];
last3[x]=l3;
other3[l3]=y;
//len[l]=z;
}
void add4(int x,int y)
{
l4++;
pre4[l4]=last4[x];
last4[x]=l4;
other4[l4]=y;
}
priority_queue<pair<ll,int> > qq;
bool vis[maxn];
ll dis[maxn];
void dijkstra(int x)
{
memset(vis,,sizeof(vis));
memset(dis,0x3f,sizeof(dis));
dis[x]=;
qq.push(make_pair(,x));
while(!qq.empty())
{
int u=qq.top().second;
qq.pop();
if(vis[u]) continue;
vis[u]=;
for(int p=last[u];p;p=pre[p])
{
int v=other[p];
if(dis[v]>dis[u]+len[p])
{
dis[v]=dis[u]+len[p];
qq.push(make_pair(-dis[v],v));
}
}
}
}
queue<int> q;
int topo[maxn],sum,in_eage[maxn];
void toposort()//此时用有向图找出拓扑序
{
for(int i=;i<=n;i++)
{
if(in_eage[i]==&&dis[i]!=dis[]) q.push(i);//此时要抛弃不在有向图上的点
}
while(!q.empty())
{
int x=q.front();
q.pop();
topo[++sum]=x;
for(int p=last2[x];p;p=pre2[p])
{
int v=other2[p];
in_eage[v]--;
if(in_eage[v]==)
{
q.push(v);
}
}
}
}
int father[maxn],f[maxn][];
int dep[maxn]; void rmq(int x)
{
f[x][]=father[x];
for(int i=;i<=;i++)
{
f[x][i]=f[f[x][i-]][i-];
}
} int LCA(int x,int y)
{
if(dep[x]<dep[y]) swap(x,y);
for(int j=;j<=;j++)
{
if((dep[x]-dep[y])&(<<j)) x=f[x][j];
}
if(x==y) return x;
for(int j=;j>=;j--)
{
if(f[x][j]!=f[y][j])
{
x=f[x][j];
y=f[y][j];
}
}
return father[x];
} void build()//重新建树的时候用反图
{
father[n+]=n+;//建立虚拟节点
f[n+][]=n+;
dep[n+]=;
for(int i=;i<=n;i++)//拓扑序从小到大开始遍历,根据反图,当前建的树的子树大小即为支配数
{
if(!topo[i]) break;//并不是所有点都在有向图上 ,但是图上的点拓扑序是连续的
int x=topo[i];
if(!last4[x])//将没有出边的点连上虚拟节点
{
dep[x]=;
father[x]=n+;
f[x][]=n+;
add3(n+,x);//3为生成的支配树
continue;
} int lca=other4[last4[x]];
for(int p=last4[x];p;p=pre4[p])
{
int v=other4[p];
lca=LCA(lca,v);
}
father[x]=lca;
dep[x]=dep[lca]+;
add3(lca,x);
rmq(x);
}
} int siz[maxn];
int ans;
void dfs(int x)
{
siz[x]=;
for(int p=last3[x];p;p=pre3[p])
{
int v=other3[p];
dfs(v);
siz[x]+=siz[v];
}
if(x!=n+&&x!=s) ans=max(ans,siz[x]);
}
int main()
{
scanf("%d%d%d",&n,&m,&s);
for(int i=;i<=m;i++)
{
int x,y;ll z;
scanf("%d%d%lld",&x,&y,&z);
add(x,y,z);
add(y,x,z);//建无向图
}
dijkstra(s);//求最短路
for(int i=;i<=n;i++)
{
for(int p=last[i];p;p=pre[p])
{
int v=other[p];
if(dis[v]==dis[i]+len[p])
{
add2(i,v);//根据最短路建立有向图
add4(v,i); //反图
in_eage[v]++;//rudu
}
}
}
toposort();
build();
dfs(n+);
printf("%d",ans);
return ;
}

CF757F Team Rocket Rises Again——最短路+支配树的更多相关文章

  1. cf757F Team Rocket Rises Again (dijkstra+支配树)

    我也想要皮卡丘 跑一遍dijkstra,可以建出一个最短路DAG(从S到任意点的路径都是最短路),然后可以在上面建支配树 并不会支配树,只能简单口胡一下在DAG上的做法 建出来的支配树中,某点的祖先集 ...

  2. CF757F Team Rocket Rises Again

    题意 建出最短路图(DAG)之后就跟这题一样了. code: #include<bits/stdc++.h> using namespace std; #define int long l ...

  3. codeforces757F Team Rocket Rises Again【支配树+倍增+拓扑+spfa】

    先跑spfa求出最短路构成的DAG,然后在DAG上跑出支配树dfs出size取max即可 关于支配树,因为是DAG,支配点就是入点在支配树上的lca,所以一边拓扑一边预处理倍增,然后用倍增求lca # ...

  4. Codeforces 757 F Team Rocket Rises Again

    Discription It's the turn of the year, so Bash wants to send presents to his friends. There are n ci ...

  5. Solution -「CF 757F」Team Rocket Rises Again

    \(\mathcal{Description}\)   link.   给定 \(n\) 个点 \(m\) 条边的无向图和一个源点 \(s\).要求删除一个不同与 \(s\) 的结点 \(u\),使得 ...

  6. codeforces 757F Team Rocket Rises Again

    链接:http://codeforces.com/problemset/problem/757/F 正解:灭绝树. mdzz倍增lca的根节点深度必须是1..我因为这个错误调了好久. 我们考虑先求最短 ...

  7. CF757F-Team Rocket Rises Again【最短路,DAG支配树】

    正题 题目链接:https://www.luogu.com.cn/problem/CF757F 题目大意 \(n\)个点\(m\)条边的一张无向图,求删除\(s\)以外的一个点改变\(s\)到最多点的 ...

  8. 康复计划#4 快速构造支配树的Lengauer-Tarjan算法

    本篇口胡写给我自己这样的老是证错东西的口胡选手 以及那些想学支配树,又不想啃论文原文的人- 大概会讲的东西是求支配树时需要用到的一些性质,以及构造支配树的算法实现- 最后讲一下把只有路径压缩的并查集卡 ...

  9. [HDU]4694 Important Sisters(支配树)

    支配树模板 #include<cstdio> #include<cstring> #include<algorithm> using namespace std; ...

随机推荐

  1. SVN_02安裝

    1.下载 TortoiseSVN  https://tortoisesvn.net/downloads.html 2.下载 VIsualSVN    https://www.visualsvn.com ...

  2. 微信小程序通讯录字母排序

    微信小程序通讯录 字母排序效果: demo地址:https://github.com/PeachCoder/wechat-contacts

  3. 无限重启:windows更新之后,在输入密码页面无限重启进入不了系统

    解决办法:windows更新之后,在输入密码页面无限重启 总体思路:进入安全模式(如何进入,下文将讲述)  -->   点击疑难解答   -->   点击高级选项  -->  点击启 ...

  4. iOS CALayer总结——图层几何

    最近看了一下关于图层和动画的内容,所以写了一份总结,算是对这些内容的汇总吧,都是一些简单的基础知识,不知道大家都了不了解. 除了和用户的交互之外,图层的很多属性和视图基本上都是一样的,今天就先从CAL ...

  5. 部署vue项目到阿里云服务器(Ubuntu16.04 64位)

    上传文件 1.通过Xftp将vue项目文件上传至云服务器:由于node_modules这个依赖包体积较大,上传较慢,上传时跳过,在云服务器上重新进行npm install安装依赖包即可: 2.也可通过 ...

  6. ceph集群部署(基于jewel版)

    环境 两个节点:ceph1.ceph2 ceph1: mon.mds.osd.0.osd.1 ceph2: osd.2.osd.3 网络配置: ceph1: 管理网络,eth0,10.0.0.20 存 ...

  7. Vue路由嵌套和命名视图

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  8. Android笔记(二十九) Android中的异步更新(一) Android中的线程

    Java中的线程 1. 线程的两种实现方式 ①继承Thread类 ②实现Runnable接口 两者区别在于,Thread这个类的对象,代表的是一个线程,而Runnable的对象,代表的是线程体(也就是 ...

  9. Flutter——TextField组件(文本框组件)

    TextField组件的常用属性: 属性 描述 maxLines 设置此参数可以把文本框改为多行文本框 onChanged 文本框改变的时候触发的事件 decoration hintText 类似 h ...

  10. C#预处理器指令——学习

    若要详细了解如何使用 C# 预处理器指令选择性地编译代码段,请参阅 #define(C# 参考)和 #if(C# 参考). #define(C# 参考) 地址:https://docs.microso ...