一道旅行者好题 By liuzhangfeiabc - 圆方树 - 学习笔记

在SDOI2018Round2比赛当场学(y)会(y)了怎么写点双以及建圆方树
但是那个题我懒得找当时写的代码了,因此不做记录,那这个题当做学习笔记
题目大意就是给你一张图,每次询问是否存在a到c到b的点不重复路径,abc互不相同。
题解,圆方树就是,新建点双个数个点,这些点称为方点,每个点向点双里面所有点连边,原图中的边不保留,特别的,点双的定义被扩展成删去任意一个点之后图联通(而不是原来的任意两点都有两条点不重复路径),这样一条边也是一个点双。这样新建出来的图是树并且只有方圆边(圆点就是原图中的点)。SDOI的那个题的结论就是虚树点的个数-|S|,而这个题的结论就是,c或fa[c]在a到b的路径上,或者fa[LCA(a,b)]==c。尽管可以线性完成上述判断,但简易的使用树剖判断即可,注意到前两个条件不需要跑两遍树剖,跑一次即可;第二个询问跑完树剖深度较浅的点的fa就是LCA。这样就可以从1100ms+卡到500ms-,效果显著。
代码:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<stack>
#include<assert.h>
#define N 200000
#define M 600000
#define gc getchar()
using namespace std;
int sta[N],dfn[N],low[N],dfc,ec,nc;
int sz[N],d[N],in[N],fa[N];
struct edges{
    int to,pre;
}e[M];int son[N],h[N],u[M],v[M];
int etop,top[N];stack<int> s;
inline int add_edge(int u,int v) { return e[++etop].to=v,e[etop].pre=h[u],h[u]=etop; }
int tarjan(int x,int fa=0)
{
    sta[x]=1,s.push(x),dfn[x]=low[x]=++dfc;
    for(int i=h[x],y;i;i=e[i].pre)
        if(!sta[y=e[i].to])
        {
            tarjan(y),low[x]=min(low[x],low[y]);
            if(low[y]>=dfn[x])
            {
                nc++;
                while(dfn[s.top()]>=dfn[y]) sta[s.top()]=2,ec++,u[ec]=nc,v[ec]=s.top(),s.pop();
                ec++,u[ec]=nc,v[ec]=x;
            }
        }
        else if(sta[y]==1&&y!=fa) low[x]=min(low[x],dfn[y]);
    return 0;
}
int fir_dfs(int x,int f)
{
    fa[x]=f,d[x]=d[f]+1,sz[x]=1;
    for(int i=h[x],y;i;i=e[i].pre)
        if((y=e[i].to)^fa[x])
        {
            sz[x]+=fir_dfs(y,x);
            if(sz[y]>sz[son[x]]) son[x]=y;
        }
    return sz[x];
}
int sec_dfs(int x)
{
    in[x]=++dfc;
    if(son[x]) top[son[x]]=top[x],sec_dfs(son[x]);
    for(int i=h[x],y;i;i=e[i].pre)
        if((y=e[i].to)!=fa[x]&&e[i].to!=son[x]) top[y]=y,sec_dfs(y);
    return 0;
}
inline int query(int x,int y,int c,int f)
{
    while(top[x]^top[y])
    {
        if(d[top[x]]<d[top[y]]) swap(x,y);
        if(in[c]<=in[x]&&in[top[x]]<=in[c]) return 1;
        if(in[f]<=in[x]&&in[top[x]]<=in[f]) return 1;
        x=fa[top[x]];
    }
    if(in[x]>in[y]) swap(x,y);
    return (in[c]>=in[x]&&in[c]<=in[y])||(in[f]>=in[x]&&in[f]<=in[y])||(fa[x]==c);
}
inline int inn()
{
    int x,ch;while((ch=gc)<'0'||ch>'9');
    x=ch^'0';while((ch=gc)>='0'&&ch<='9')
        x=(x<<1)+(x<<3)+(ch^'0');return x;
}
int main()
{
    int n=inn(),m=inn(),q=inn(),a,b,c;
    for(int i=1,u,v;i<=m;i++)
        u=inn(),v=inn(),add_edge(u,v),add_edge(v,u);
    nc=n,ec=0,tarjan(1),memset(h,0,sizeof(h)),etop=0;
    for(int i=1;i<=ec;i++) add_edge(u[i],v[i]),add_edge(v[i],u[i]);
    n=nc,fir_dfs(1,0),top[1]=1,dfc=0,sec_dfs(1);
    while(q--) a=inn(),c=inn(),b=inn(),printf("%s\n",query(a,b,c,fa[c])?"yes":"no");
    return 0;
}
阅读更多
换一批

没有更多推荐了,返回首页