正题

题目链接:https://www.luogu.com.cn/problem/P7737


题目大意

给出一张无向图满足若\(x\Rightarrow z,y\Rightarrow z\)那么有\(x\Rightarrow y\)或\(y\Rightarrow x\)。

\(q\)次询问给出起点和终点和\(k\)条临时的边,求可能经过点的数量

\(1\leq n,q\leq 3\times 10^5,0\leq k\leq 2\)


解题思路

那个条件就是说我们缩点之后可以找出一个联通性和原图相同的树。

先缩点然后和原图相同的树的话我们用拓扑排序找,让每个点入栈的那个点就是它的父节点。

然后因为最多加两条边所以我们可以把有影响的点找出来构成一棵虚树然后暴力跑出答案就好了。

时间复杂度\(O(n+Qk)\)


code

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<stack>
#include<queue>
#include<cctype>
#include<iostream>
using namespace std;
const int N=3e5+10,Z=18;
struct node{
int to,next,w;
}a[N];
int n,m,Q,k,dcc,cnt,dfr,top,tot,clt,ans,num,p[7];
int dfn[N],low[N],v[N],ls[N],rt[N],cl[N],dep[N];
int f[N][Z+1],col[N],siz[N],in[N],st[N],dis[N],ed[N];
bool ins[N];stack<int>S;queue<int>q;
vector<int>G[N],F[N],T[N],D[N];
inline char Getchar()
{
static char buf[100000],*p1=buf+100000,*pend=buf+100000;
if(p1==pend)
{
p1=buf; pend=buf+fread(buf,1,100000,stdin);
if (pend==p1) return -1;
}
return *p1++;
}
inline int read()
{
char c;int d=1;int f=0;
while(c=Getchar(),!isdigit(c))if(c==45)d=-1;f=(f<<3)+(f<<1)+c-48;
while(c=Getchar(),isdigit(c)) f=(f<<3)+(f<<1)+c-48;
return d*f;
}
inline void tarjan(int x){
dfn[x]=low[x]=++cnt;
ins[x]=1;S.push(x);
for(int i=0;i<G[x].size();i++){
int y=G[x][i];
if(!dfn[y]){
tarjan(y);
low[x]=min(low[x],low[y]);
}
else if(ins[y])
low[x]=min(low[x],dfn[y]);
}
if(low[x]==dfn[x]){
++dcc;
while(S.top()!=x){
col[S.top()]=dcc;
ins[S.top()]=0;
siz[dcc]++;S.pop();
}
col[x]=dcc;ins[x]=0;
siz[dcc]++;S.pop();
}
return;
}
inline void Topsort(){
for(int i=1;i<=dcc;i++)
if(!in[i])rt[i]=i,q.push(i);
while(!q.empty()){
int x=q.front();q.pop();
for(int i=0;i<F[x].size();i++){
int y=F[x][i];in[y]--;
if(!in[y]){
q.push(y);
T[x].push_back(y);
}
}
}
return;
}
inline void dfs(int x,int fa){
dis[x]=dis[fa]+siz[x];
dep[x]=dep[fa]+1;dfn[x]=++dfr;
for(int i=0;i<T[x].size();i++){
int y=T[x][i];
if(y==fa)continue;
f[y][0]=x;rt[y]=rt[x];
dfs(y,x);
}
ed[x]=dfr;return;
}
inline int LCA(int x,int y){
if(dep[x]>dep[y])swap(x,y);
for(int i=Z;i>=0;i--)
if(dep[f[y][i]]>=dep[x])y=f[y][i];
if(x==y)return x;
for(int i=Z;i>=0;i--)
if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
return f[x][0];
}
inline bool cmp(int x,int y)
{return dfn[x]<dfn[y];}
inline void addl(int x,int y,int w){
a[++tot].to=y;
a[tot].next=ls[x];
a[tot].w=(dis[y]-dis[x]-siz[y])*w;
D[y].push_back(x);ls[x]=tot;return;
}
inline void Add(int x){
if(rt[st[top]]!=rt[x]){
while(top>1)addl(st[top-1],st[top],1),top--;
if(x!=rt[x])st[top]=rt[x],cl[++clt]=x;
}
if(!top){st[++top]=x;cl[++clt]=x;return;}
int lca=LCA(st[top],x);
while(top>1&&dep[st[top-1]]>dep[lca])
addl(st[top-1],st[top],1),top--;
if(dep[st[top]]>dep[lca])addl(lca,st[top],1),top--;
if((!top)||(st[top]!=lca))st[++top]=lca,cl[++clt]=lca;
st[++top]=x;cl[++clt]=x;
}
inline void mark(int x){
v[x]=1;
for(int i=0;i<D[x].size();i++)
if(!v[D[x][i]])
mark(D[x][i]);
return;
}
inline void calc(int x){
if(v[x])ans+=siz[x];v[x]|=2;
for(int i=ls[x];i;i=a[i].next){
int y=a[i].to;
if(v[y]&1)ans+=a[i].w,a[i].w=0;
if((v[y]&2)||!(v[y]&1))continue;
calc(y);
}
return;
}
signed main()
{
freopen("P7737_12.in","r",stdin);
freopen("data.out","w",stdout);
n=read();m=read();Q=read();k=read();
for(int i=1;i<=m;i++){
int x=read(),y=read();
G[x].push_back(y);
}
for(int i=1;i<=n;i++)
if(!dfn[i])tarjan(i);
for(int x=1;x<=n;x++)
for(int i=0;i<G[x].size();i++){
int y=G[x][i];
if(col[x]==col[y])continue;
F[col[x]].push_back(col[y]);in[col[y]]++;
}
Topsort();n=dcc;
for(int i=1;i<=n;i++)
if(rt[i]==i)dfs(rt[i],0);
for(int j=1;j<=Z;j++)
for(int i=1;i<=n;i++)
f[i][j]=f[f[i][j-1]][j-1];
while(Q--){
int s=read(),t=read();
s=col[s];t=col[t];
p[1]=s;p[2]=t;num=2;
tot=clt=top=ans=0;
for(int i=1;i<=k;i++){
int x=read(),y=read();
x=col[x];y=col[y];
p[++num]=x;p[++num]=y;
addl(x,y,0);
}
sort(p+1,p+1+num,cmp);
num=unique(p+1,p+1+num)-p-1;
for(int i=1;i<=num;i++)Add(p[i]);
while(top>1)addl(st[top-1],st[top],1),top--;
mark(t);calc(s);
cout<<ans<<'\n';
for(int i=1;i<=clt;i++){
ls[cl[i]]=v[cl[i]]=0;
if(D[cl[i]].size())D[cl[i]].clear();
}
}
return 0;
}

P7737-[NOI2021]庆典【tarjan,虚树】的更多相关文章

  1. [Codeforces 639F] Bear and Chemistry (Tarjan+虚树)(有详细注释)

    [Codeforces 639F] Bear and Chemistry(Tarjan+虚树) 题面 给出一个n个点,m条边的无向图(不保证连通,可能有自环和重边),有q次询问,每次询问给出p个点和q ...

  2. 图论杂项细节梳理&模板(虚树,圆方树,仙人掌,欧拉路径,还有。。。)

    orzYCB 虚树 %自为风月马前卒巨佬% 用于优化一类树形DP问题. 当状态转移只和树中的某些关键点有关的时候,我们把这些点和它们两两之间的LCA弄出来,以点的祖孙关系连成一棵新的树,这就是虚树. ...

  3. Luogu4606 SDOI2018 战略游戏 圆方树、虚树、链并

    传送门 弱化版 考虑到去掉一个点使得存在两个点不连通的形式类似割点,不难想到建立圆方树.那么在圆方树上对于给出的关键点建立虚树之后,我们需要求的就是虚树路径上所有圆点的数量减去关键点的数量. 因为没有 ...

  4. 仙人掌 && 圆方树 && 虚树 总结

    仙人掌 && 圆方树 && 虚树 总结 Part1 仙人掌 定义 仙人掌是满足以下两个限制的图: 图完全联通. 不存在一条边处在两个环中. 其中第二个限制让仙人掌的题做 ...

  5. Codechef Sad Pairs——圆方树+虚树+树上差分

    SADPAIRS 删点不连通,点双,圆方树 非割点:没有影响 割点:子树DP一下 有不同颜色,所以建立虚树 在圆方树上dfs时候 如果当前点是割点 1.统计当前颜色虚树上的不连通点对,树形DP即可 2 ...

  6. 算法笔记--树的直径 && 树形dp && 虚树 && 树分治 && 树上差分 && 树链剖分

    树的直径: 利用了树的直径的一个性质:距某个点最远的叶子节点一定是树的某一条直径的端点. 先从任意一顶点a出发,bfs找到离它最远的一个叶子顶点b,然后再从b出发bfs找到离b最远的顶点c,那么b和c ...

  7. BZOJ5329:[SDOI2018]战略游戏(圆方树,虚树)

    Description 省选临近,放飞自我的小Q无心刷题,于是怂恿小C和他一起颓废,玩起了一款战略游戏. 这款战略游戏的地图由n个城市以及m条连接这些城市的双向道路构成,并且从任意一个城市出发总能沿着 ...

  8. Luogu P4606 [SDOI2018] 战略游戏 圆方树 虚树

    https://www.luogu.org/problemnew/show/P4606 把原来的图的点双联通分量缩点(每个双联通分量建一个点,每个割点再建一个点)(用符合逻辑的方式)建一棵树(我最开始 ...

  9. BZOJ.5329.[SDOI2018]战略游戏(圆方树 虚树)

    题目链接 显然先建圆方树,方点权值为0圆点权值为1,两点间的答案就是路径权值和减去起点终点. 对于询问,显然可以建虚树.但是只需要计算两关键点间路径权值,所以不需要建出虚树.统计DFS序相邻的两关键点 ...

随机推荐

  1. arthas-Java诊断工具

    Arthas 是Alibaba开源的Java诊断工具,深受开发者喜爱. 官网:https://arthas.aliyun.com/zh-cn/ 当你遇到以下类似问题而束手无策时,Arthas可以帮助你 ...

  2. 详解 OpenGL ES 2.x 渲染流程

    khronos官方对OpenGL ES的描述如下: OpenGL ES is a royalty-free, cross-platform API for rendering advanced 2D ...

  3. Mybatis框架及原理实例分析

    摘要 本篇文章只是个人阅读mybatis源码总结的经验或者个人理解mybatis的基本轮廓,作为抛砖引玉的功能,希望对你有帮助,如果需要深入了解细节还需亲自去阅读源码. mybatis基本架构 myb ...

  4. GIT基础篇,配置账号及命令查看以及帮助命令

    提交用户名和邮件地址   1 安装完Git首先要设置你的用户名称与邮件地址.每一个Git的提交都会使用这些信息,并且它会写入到你的每一次提交中. 2 git config --global user. ...

  5. HttpClient 4.3教程-前言

    前言 Http协议应该是互联网中最重要的协议.持续增长的web服务.可联网的家用电器等都在继承并拓展着Http协议,向着浏览器之外的方向发展. 虽然jdk中的java.net包中提供了一些基本的方法, ...

  6. Quartz任务调度(1)概念例析快速

    实例解析概念 在quartz中,有几个核心类和接口:Job.JobDetail.Trigger.Calendar.Scheduler.下面我们结合实例来分析这些类的角色定位.现在我们有一个新闻网站,它 ...

  7. Python - 面向对象编程 - 公共属性、保护属性、私有属性

    公共属性 在 Python 的类里面,所有属性和方法默认都是公共的 class PoloBlog: # 公共属性 sum = 0 # 构造方法 def __init__(self, name): se ...

  8. 最全华为鸿蒙 HarmonyOS 开发资料汇总

    开发 本示例基于 OpenHarmony 下的 JavaScript UI 框架,进行项目目录解读,JS FA.常用和自定义组件.用户交互.JS 动画的实现,通过本示例可以基本了解和学习到 JavaS ...

  9. python入门-变量与数据类型

    1.命名规则 变量名只能包含字母.数字和下划线.但不能以数字打头. 变量名不能包含空格 不能与关键字冲突 变量名应尽量简短且具有描述性 2.字符串 python中引号括起的内容,其中引号可以为单引号或 ...

  10. VS Code闪现,巨头纷纷入局的Web IDE缘何崛起?

    我发了,我装的. 就在前几天,微软简短的发布了Visual Studio Code for the Web 的公告,而没过一阵,这则公告就被删除了,现在点经相关内容已经是404状态了.虽然公告的内容已 ...