• 【BZOJ3772】精神污染 DFS序+主席树


    【BZOJ3772】精神污染

    Description

    兵库县位于日本列岛的中央位置,北临日本海,南面濑户内海直通太平洋,中央部位是森林和山地,与拥有关西机场的大阪府比邻而居,是关西地区面积最大的县,是集经济和文化于一体的一大地区,是日本西部门户,海陆空交通设施发达。濑户内海沿岸气候温暖,多晴天,有日本少见的贸易良港神户港所在的神户市和曾是豪族城邑“城下町”的姬路市等大城市,还有以疗养地而闻名的六甲山地等。
    兵库县官方也大力发展旅游,为了方便,他们在县内的N个旅游景点上建立了n-1条观光道,构成了一棵图论中的树。同时他们推出了M条观光线路,每条线路由两个节点x和y指定,经过的旅游景点就是树上x到y的唯一路径上的点。保证一条路径只出现一次。
    你和你的朋友打算前往兵库县旅游,但旅行社还没有告知你们最终选择的观光线路是哪一条(假设是线路A)。这时候你得到了一个消息:在兵库北有一群丧心病狂的香菜蜜,他们已经选定了一条观光线路(假设是线路B),对这条路线上的所有景点都释放了【精神污染】。这个计划还有可能影响其他的线路,比如有四个景点1-2-3-4,而【精神污染】的路径是1-4,那么1-3,2-4,1-2等路径也被视为被完全污染了。
    现在你想知道的是,假设随便选择两条不同的路径A和B,存在一条路径使得如果这条路径被污染,另一条路径也被污染的概率。换句话说,一条路径被另一条路径包含的概率。

    Input

    第一行两个整数N,M
    接下来N-1行,每行两个数a,b,表示A和B之间有一条观光道。
    接下来M行,每行两个数x,y,表示一条旅游线路。

    Output

    所求的概率,以最简分数形式输出。

    Sample Input

    5 3
    1 2
    2 3
    3 4
    2 5
    3 5
    2 5
    1 4

    Sample Output

    1/3
    样例解释
    可以选择的路径对有(1,2),(1,3),(2,3),只有路径1完全覆盖路径2。

    HINT

    100%的数据满足:N,M<=100000
    (题意只有最后一句是有用的,其余都是废话。)
    题解:理解一下:对于每一个询问x,y,将y的子树中的所有节点都加到x的子树中的所有线段树中去。
    具体做法:离散化+DFS处理入栈出栈序+求LCA+主席树
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    const int maxn=100010;
    int n,m,cnt,tot,nm;
    long long ans,dev;
    int to[maxn<<1],next[maxn<<1],head[maxn],qt[maxn],qn[maxn],qh[maxn],root[maxn<<1];
    int size[maxn],top[maxn],fa[maxn],son[maxn],deep[maxn],Q[maxn<<1],qin[maxn],qout[maxn];
    struct node
    {
        int sum,ls,rs;
    }s[maxn*39];
    int readin()
    {
        int ret=0,f=1;    char gc=getchar();
        while(gc<'0'||gc>'9')    {if(gc=='-')f=-f;gc=getchar();}
        while(gc>='0'&&gc<='9')    ret=ret*10+gc-'0',gc=getchar();
        return ret*f;
    }
    void add(int a,int b)
    {
        to[cnt]=b;
        next[cnt]=head[a];
        head[a]=cnt++;
    }
    void dfs1(int x)
    {
        size[x]=1;
        Q[++Q[0]]=x;
        qin[x]=++nm;
        for(int i=head[x];i!=-1;i=next[i])
        {
            if(to[i]!=fa[x])
            {
                fa[to[i]]=x;
                deep[to[i]]=deep[x]+1;
                dfs1(to[i]);
                size[x]+=size[to[i]];
                if(size[to[i]]>size[son[x]])    son[x]=to[i];
            }
        }
        qout[x]=++nm;
    }
    void dfs2(int x,int tp)
    {
        top[x]=tp;
        if(son[x])    dfs2(son[x],tp);
        for(int i=head[x];i!=-1;i=next[i])
            if(to[i]!=son[x]&&to[i]!=fa[x])
                dfs2(to[i],to[i]);
    }
    int getlca(int x,int y)
    {
        while(top[x]!=top[y])
        {
            if(deep[top[x]]>deep[top[y]])    x=fa[top[x]];
            else    y=fa[top[y]];
        }
        if(deep[x]>deep[y])    return y;
        return x;
    }
    void insert(int x,int &y,int l,int r,int pos,int val)
    {
        if(pos>r)    return ;
        y=++tot;
        if(l==r)
        {
            s[y].sum=s[x].sum+val;
            return ;
        }
        int mid=l+r>>1;
        if(pos<=mid)    s[y].rs=s[x].rs,insert(s[x].ls,s[y].ls,l,mid,pos,val);
        else    s[y].ls=s[x].ls,insert(s[x].rs,s[y].rs,mid+1,r,pos,val);
        s[y].sum=s[s[y].ls].sum+s[s[y].rs].sum;
    }
    int query(int x1,int x2,int x3,int x4,int l,int r,int a,int b)
    {
        if(a<=l&&r<=b)
            return s[x1].sum+s[x2].sum-s[x3].sum-s[x4].sum;
        int mid=l+r>>1;
        if(b<=mid)
            return query(s[x1].ls,s[x2].ls,s[x3].ls,s[x4].ls,l,mid,a,b);
        if(a>mid)
            return query(s[x1].rs,s[x2].rs,s[x3].rs,s[x4].rs,mid+1,r,a,b);
        return query(s[x1].ls,s[x2].ls,s[x3].ls,s[x4].ls,l,mid,a,b)+
            query(s[x1].rs,s[x2].rs,s[x3].rs,s[x4].rs,mid+1,r,a,b);
    }
    long long gcd(long long a,long long b)
    {
        return (b==0)?a:gcd(b,a%b);
    }
    int main()
    {
        n=readin(),m=readin();
        int i,j,a,b,c;
        memset(head,-1,sizeof(head));
        for(i=1;i<n;i++)
        {
            a=readin(),b=readin();
            add(a,b),add(b,a);
        }
        deep[1]=1;
        dfs1(1),dfs2(1,1);
        for(i=1;i<=m;i++)
        {
            a=readin(),b=readin();
            qt[i]=b;
            qn[i]=qh[a];
            qh[a]=i;
        }
        for(i=1;i<=n;i++)
        {
            a=Q[i];
            root[a]=root[fa[a]];
            for(j=qh[a];j;j=qn[j])
            {
                b=qt[j];
                insert(root[a],root[a],1,nm,qin[b],1),insert(root[a],root[a],1,nm,qout[b],-1);
            }
        }
        for(i=1;i<=n;i++)
        {
            a=i;
            for(j=qh[a];j;j=qn[j])
            {
                b=qt[j];
                c=getlca(a,b);
                ans+=query(root[a],root[b],root[c],root[fa[c]],1,nm,qin[c],qin[a]);
                ans+=query(root[a],root[b],root[c],root[fa[c]],1,nm,qin[c],qin[b]);
                ans-=query(root[a],root[b],root[c],root[fa[c]],1,nm,qin[c],qin[c]);
                ans--;
            }
        }
        dev=(long long)m*(m-1)/2;
        long long temp=gcd(ans,dev);
        printf("%lld/%lld",ans/temp,dev/temp);
        return 0;
    }
  • 相关阅读:
    游戏保护硬件检测
    Debugging the Ubuntu kernel with GDB and QEMU
    Spring 校验器(Validator)
    Visual Studio添加自定义代码片段
    加载内核符号 使用 VMware 的 GDB 存根和 IDA Pro 进行 VMM 调试
    遍历PspCidTable表检测隐藏进程
    KVM/QEMU(virtmanager)使用iso镜像安装macOS bigsur 11.4
    Mysql慢查询的一次奇葩经历,group by慢查询终极解决方案!
    es6 findIndex,find用法
    prototype 用法
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/6296432.html
Copyright © 2020-2023  润新知