• [NOIP模拟]相遇/行程的交集


    Description

    豪哥生活在一个 n 个点的树形城市里面,每一天都要走来走去。虽然走的是比较的 多,但是豪哥在这个城市里面的朋友并不是很多。 当某一天,猴哥给他展现了一下大佬风范之后,豪哥决定要获得一些交往机会来提升交 往能力。豪哥现在已经物色上了一条友,打算和它(豪哥并不让吃瓜群众知道性别)交 往。豪哥现在 spy 了一下这个人的所有行程起点和终点,豪哥打算从终点开始走到起点与 其相遇。但是豪哥是想找话题的,他想知道以前有多少次行程和此次行程是有交集的,这 样豪哥就可以搭上话了。这个路径与之前路径的有交集数量作为豪哥此次的交往机会。 但是豪哥急着要做交往准备,所以算什么交往机会的小事情就交给你了。

    Solution

    如果两条路径有交集,只可能是以下两种情况:

    • 此条路径的lca在之前某条路径上
    • 之前某条路径的lca在此条路径上

    这两个情况有交集——两条路径的lca重合,所以统计答案时可以这样操作:

    • 更新答案:
      • 在A树中将此条路径的lca的子树全部+1
      • 在B树中将此条路径两端点+1,lca-2
    • 统计答案:
      • 统计在A树中两端点到根的路径减去lca到根的路径上lca数量
      • 统计在B树中lca的子树
      • lca重合的情况特判

    可以用树状数组处理

    #include<iostream>
    #include<cstdio>
    using namespace std;
    int n,m,fa[200005][25],st[200005],ed[200005],cnt,dep[200005],sum[200005],ans,head[200005],tot;
    struct Edge
    {
        int to,nxt;
    }edge[400005];
    int lowbit(int x)
    {
        return x&-x;
    }
    struct Tree
    {
        int tree[200005];
        void add(int pos,int v)
        {
            while(pos<=n)
            {
                tree[pos]+=v;
                pos+=lowbit(pos);
            }
        }
        int query(int pos)
        {
            int ret=0;
            while(pos)
            {
                ret+=tree[pos];
                pos-=lowbit(pos);
            }
            return ret;
        }
    }tr1,tr2;
    inline int read()
    {
        int f=1,w=0;
        char ch=0;
        while(ch<'0'||ch>'9')
        {
            if(ch=='-')
                f=-1;
            ch=getchar();
        }
        while(ch>='0'&&ch<='9')
        {
            w=(w<<1)+(w<<3)+ch-'0';
            ch=getchar();
        }
        return f*w;
    }
    void dfs(int k,int f)
    {
        fa[k][0]=f;
        st[k]=++cnt;
        dep[k]=dep[f]+1;
        for(int i=1;i<=20;i++)
        {
            fa[k][i]=fa[fa[k][i-1]][i-1];
        }
        for(int i=head[k];i;i=edge[i].nxt)
        {
            int v=edge[i].to;
            if(v==f)
            {
                continue;
            }
            dfs(v,k);
        }
        ed[k]=cnt;
    }
    int lca(int x,int y)
    {
        if(dep[x]<dep[y])
        {
            swap(x,y);
        }
        for(int i=20;i>=0;i--)
        {
            if(dep[fa[x][i]]>=dep[y])
            {
                x=fa[x][i];
            }
        }
        if(x==y)
        {
            return x;
        }
        for(int i=20;i>=0;i--)
        {
            if(fa[x][i]!=fa[y][i])
            {
                x=fa[x][i];
                y=fa[y][i];
            }
        }
        return fa[x][0];
    }
    int main()
    {
        n=read();
        for(int i=1;i<n;i++)
        {
            int u=read(),v=read();
            edge[++tot]=(Edge){v,head[u]};
            head[u]=tot;
            edge[++tot]=(Edge){u,head[v]};
            head[v]=tot;
        }
        dfs(1,0);
        m=read();
        for(int i=1;i<=m;i++)
        {
            int u=read(),v=read(),x=lca(u,v);
            printf("%d
    ",tr1.query(st[v])+tr1.query(st[u])-2*tr1.query(st[x])+tr2.query(ed[x])-tr2.query(st[x]-1)+sum[x]);
            sum[x]++;
            tr1.add(st[x],1);
            tr1.add(ed[x]+1,-1);
            tr2.add(st[u],1);
            tr2.add(st[v],1);
            tr2.add(st[x],-2);
        }
        return 0;
    }
    相遇
  • 相关阅读:
    牛客刷题-解密
    使用vue-awesome-swiper插件制作轮播图
    在vue项目中使用iconfont
    使用JS配合表单上传图片并预览
    JS购物车(3)-Ajax发送POST请求提交订单
    JS购物车(2)-全选/全不选的勾选框
    JS购物车(1)-数量增减框
    mysql笔记(14)-用户、角色与权限
    git分支管理(3)-fast forward和no fast forward
    git分支管理(2)-解决冲突
  • 原文地址:https://www.cnblogs.com/JDFZ-ZZ/p/13387941.html
Copyright © 2020-2023  润新知