zoukankan      html  css  js  c++  java
  • 洛谷 P3398 仓鼠找sugar 解题报告

    P3398 仓鼠找sugar

    题目描述

    小仓鼠的和他的基(mei)友(zi)sugar住在地下洞穴中,每个节点的编号为1~n。地下洞穴是一个树形结构。这一天小仓鼠打算从从他的卧室(a)到餐厅(b),而他的基友同时要从他的卧室(c)到图书馆(d)。他们都会走最短路径。现在小仓鼠希望知道,有没有可能在某个地方,可以碰到他的基友?

    小仓鼠那么弱,还要天天被zzq大爷虐,请你快来救救他吧!

    输入输出格式

    输入格式:

    第一行两个正整数n和q,表示这棵树节点的个数和询问的个数。

    接下来n-1行,每行两个正整数u和v,表示节点u到节点v之间有一条边。

    接下来q行,每行四个正整数a、b、c和d,表示节点编号,也就是一次询问,其意义如上。

    输出格式:

    对于每个询问,如果有公共点,输出大写字母“Y”;否则输出“N”。


    (1)暴力树链剖分

    每次查询对路径((a,b))染色,然后走路径((c,d)),最后把颜色还原

    Code:

    #include <cstdio>
    #include <cstring>
    #define ls id<<1
    #define rs id<<1|1
    int max(int x,int y){return x>y?x:y;}
    int min(int x,int y){return x<y?x:y;}
    const int N=100010;
    int head[N],to[N<<1],Next[N<<1],cnt;
    void add(int u,int v)
    {
        to[++cnt]=v;Next[cnt]=head[u];head[u]=cnt;
    }
    int color[N<<2],lazy[N<<2];
    int dfn[N],top[N],siz[N],dep[N],ws[N],f[N],time,n,q;
    void dfs1(int now,int fa)
    {
        siz[now]++;
        for(int i=head[now];i;i=Next[i])
        {
            int v=to[i];
            if(v!=fa)
            {
                dep[v]=dep[now]+1;
                f[v]=now;
                dfs1(v,now);
                siz[now]+=siz[v];
                if(siz[ws[now]]<siz[v])
                    ws[now]=v;
            }
        }
    }
    void dfs2(int now,int anc)
    {
        dfn[now]=++time;
        top[now]=anc;
        if(ws[now]) dfs2(ws[now],anc);
        for(int i=head[now];i;i=Next[i])
            if(!dfn[to[i]])
                dfs2(to[i],to[i]);
    }
    void push_down(int id,int l,int r)
    {
        if(lazy[id]==-1) return;
        if(l!=r) lazy[ls]=lazy[rs]=color[ls]=color[rs]=lazy[id];
        lazy[id]=-1;
    }
    void change(int id,int l,int r,int L,int R,int c)
    {
        push_down(id,L,R);
        if(l==L&&r==R)
        {
            color[id]=c;
            lazy[id]=c;
            return;
        }
        int Mid=L+R>>1;
        if(r<=Mid)
            change(ls,l,r,L,Mid,c);
        else if(l>Mid)
            change(rs,l,r,Mid+1,R,c);
        else
            change(ls,l,Mid,L,Mid,c),change(rs,Mid+1,r,Mid+1,R,c);
        color[id]=max(color[ls],color[rs]);
    }
    int query(int id,int l,int r,int L,int R)
    {
        push_down(id,L,R);
        if(l==L&&r==R)
            return color[id];
        int Mid=L+R>>1;
        if(r<=Mid)
            return query(ls,l,r,L,Mid);
        else if(l>Mid)
            return query(rs,l,r,Mid+1,R);
        else
            return max(query(ls,l,Mid,L,Mid),query(rs,Mid+1,r,Mid+1,R));
    }
    char C[2]={'N','Y'};
    int t_query(int x,int y)
    {
        int ans=0;
        while(top[x]!=top[y])
        {
            if(dep[top[x]]>dep[top[y]])
            {
                ans=query(1,dfn[top[x]],dfn[x],1,n);
                if(ans) return 1;
                x=f[top[x]];
            }
            else
            {
                ans=query(1,dfn[top[y]],dfn[y],1,n);
                if(ans) return 1;
                y=f[top[y]];
            }
        }
        return query(1,min(dfn[x],dfn[y]),max(dfn[x],dfn[y]),1,n);
    }
    void t_change(int x,int y,int c)
    {
        while(top[x]!=top[y])
        {
            if(dep[top[x]]>dep[top[y]])
            {
                change(1,dfn[top[x]],dfn[x],1,n,c);
                x=f[top[x]];
            }
            else
            {
                change(1,dfn[top[y]],dfn[y],1,n,c);
                y=f[top[y]];
            }
        }
        change(1,min(dfn[x],dfn[y]),max(dfn[x],dfn[y]),1,n,c);
    }
    int main()
    {
        scanf("%d%d",&n,&q);
        memset(lazy,-1,sizeof(lazy));
        int a,b,c,d;
        for(int i=1;i<n;i++)
        {
            scanf("%d%d",&a,&b);
            add(a,b),add(b,a);
        }
        dfs1(1,0);
        dfs2(1,1);
        for(int i=1;i<=q;i++)
        {
            scanf("%d%d%d%d",&a,&b,&c,&d);
            t_change(a,b,1);
            printf("%c
    ",C[t_query(c,d)]);
            t_change(a,b,0);
        }
        return 0;
    }
    
    

    (2)手玩观察的LCA写法

    我们发现,路径往上走的时候是唯一的。那么如果有交点的话,最高点(也就是LCA)较低路径的最高点一定在另一条路径上。

    问题就变成了查询某个点是否在一条路径上。我们只需要查询两个端点和这个点的LCA是否是这个点就行啦

    没有代码


    2018.7.13

  • 相关阅读:
    C/C++学习笔记1
    好文章
    mosquitto.conf之log配置
    安装mosquitto报缺少dll文件的错误
    mysql分页性能
    mysql慢日志记录
    sql执行计划
    sql之临时表
    mysqldump
    最全的常用正则表达式大全——包括校验数字、字符、一些特殊的需求等等
  • 原文地址:https://www.cnblogs.com/butterflydew/p/9305915.html
Copyright © 2011-2022 走看看