• [BZOJ3772]精神污染 主席树上树+欧拉序


    3772: 精神污染

    Time Limit: 10 Sec  Memory Limit: 64 MB

    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
     
    题解:
    这道题真是精神污染……
    首先,最重要的,本题卡内存,建议用数组打/开内存池重载new
    接下来,我们来分析题目:一条路径被另一条路径包含的概率,等于包含的情况数除以所有路径组合。
    即SUM/C(n)(2)。现在的问题转变为求SUM。
    不难发现,如果一条路径A被一条路径B包含,那么A的两端点都在B内。
    所以对于B路径,它包含路径的条数可以通过下面的方法求:枚举路径上的每一个点,看从这个点出发的路径有几条的终点也在B内。
    这时候我们就需要一种区间可减的数据结构来维护信息……
    显然是主席树,然后用欧拉序(似乎叫括号序更恰当)统计。不了解的同学可以去我之前的博客找一波讲解。
    不过注意,对于本题来说,由于我们统计的是边,所以我们应该统计[x.lca]和[y.lca]。
    lca处的答案被统计了2次,最后记得减去;并且,自己不能覆盖自己,统计完之后还要-1才行。
    这样本题就被我们解决了:) 代码见下:
     1 #include <cstdio>
     2 #include <cstring>
     3 #include <algorithm>
     4 #include <vector>
     5 using namespace std;
     6 typedef long long LL;
     7 const int N=100005;
     8 vector<int>vec[N];
     9 int n,m,num,deep[N],adj[N],e,l[N],r[N];
    10 struct edge{int zhong,next;}s[N<<1];
    11 inline void add(int qi,int zhong){s[++e].zhong=zhong;s[e].next=adj[qi];adj[qi]=e;}
    12 struct data{int qi,zhong;}ro[N];
    13 inline bool mt(const data &a,const data &b){return (a.qi==b.qi)?a.zhong<b.zhong:a.qi<b.qi;}
    14 struct node
    15 {
    16     node *ch[2];int cnt;
    17     void* operator new (size_t,node *a,node *b,int c)  
    18     {  
    19         static node mempool[N*38],*C=mempool;  
    20         C->ch[0]=a,C->ch[1]=b,C->cnt=c;  
    21         return C++;  
    22     }  
    23     node* insert(int l,int r,int pos,int val)
    24     {
    25         if(l==r)return new (NULL,NULL,this->cnt+val)node;
    26         int mi=(l+r)>>1;
    27         if(pos<=mi) return new (ch[0]->insert(l,mi,pos,val),ch[1],this->cnt+val)node;
    28         else return new (ch[0],ch[1]->insert(mi+1,r,pos,val),this->cnt+val)node;
    29     }
    30 }*root[N];
    31 int query(node *a,node *b,node *c,node *d,int le,int ri,int L,int R)
    32 {
    33     if(L<=le&&ri<=R)return a->cnt+b->cnt-c->cnt-d->cnt;
    34     int ret=0,mi=(le+ri)>>1;
    35     if(L<=mi)ret+=query(a->ch[0],b->ch[0],c->ch[0],d->ch[0],le,mi,L,R);
    36     if(mi<R)ret+=query(a->ch[1],b->ch[1],c->ch[1],d->ch[1],mi+1,ri,L,R);
    37     return ret;
    38 }
    39 
    40 int f[N][18],bin[25];
    41 inline int LCA(int a,int b)
    42 {
    43     if(deep[a]<deep[b])swap(a,b);
    44     int cha=deep[a]-deep[b];
    45     for(int j=17;~j;j--)
    46         if(cha&bin[j])a=f[a][j];
    47     if(a==b)return a;
    48     for(int j=17;~j;j--)
    49         if(f[a][j]!=f[b][j])a=f[a][j],b=f[b][j];
    50     return f[a][0];
    51 }
    52 
    53 void dfs1(int rt,int fa)
    54 {
    55     l[rt]=++num;deep[rt]=deep[fa]+1;
    56     for(int i=adj[rt];i;i=s[i].next)
    57         if(s[i].zhong!=fa)f[s[i].zhong][0]=rt,dfs1(s[i].zhong,rt);
    58     r[rt]=++num;
    59 }  
    60 void dfs2(int rt,int fa)
    61 {
    62     root[rt]=root[fa];
    63     for(int i=0,len=vec[rt].size();i<len;i++)
    64     {
    65         root[rt]=root[rt]->insert(1,n<<1,l[vec[rt][i]],1);
    66         root[rt]=root[rt]->insert(1,n<<1,r[vec[rt][i]],-1);
    67     }
    68     for(int i=adj[rt];i;i=s[i].next)
    69         if(s[i].zhong!=fa)dfs2(s[i].zhong,rt);
    70 }
    71 LL Z,M;
    72 LL gcd(LL a,LL b){return (b==0)?a:gcd(b,a%b);}
    73 
    74 int main()
    75 {
    76     scanf("%d%d",&n,&m);int a,b;
    77     for(int i=1;i<n;i++)scanf("%d%d",&a,&b),add(a,b),add(b,a);
    78     for(int i=1;i<=m;i++)
    79         scanf("%d%d",&ro[i].qi,&ro[i].zhong),vec[ro[i].qi].push_back(ro[i].zhong);
    80     root[0]=new (NULL,NULL,0) node;
    81     root[0]->ch[0]=root[0]->ch[1]=root[0];
    82     dfs1(1,0);dfs2(1,0);
    83     bin[0]=1;for(int i=1;i<=20;i++)bin[i]=bin[i-1]<<1;
    84     for(int j=1;j<=17;j++)
    85         for(int i=1;i<=n;i++)
    86             f[i][j]=f[f[i][j-1]][j-1];
    87     for(int i=1;i<=m;i++)
    88     {
    89         int lca=LCA(ro[i].qi,ro[i].zhong),t=f[lca][0];
    90         a=ro[i].qi,b=ro[i].zhong;
    91         Z+=query(root[a],root[b],root[lca],root[t],1,n<<1,l[lca],l[a]);
    92         Z+=query(root[a],root[b],root[lca],root[t],1,n<<1,l[lca],l[b]);
    93         Z-=query(root[a],root[b],root[lca],root[t],1,n<<1,l[lca],l[lca]);
    94         Z--;
    95     }
    96     M=(LL)m*(m-1)>>1;LL tmp=gcd(Z,M);
    97     printf("%lld/%lld",Z/tmp,M/tmp);
    98 }
  • 相关阅读:
    docker
    perl有用的字符串匹配
    nginx 反向代理 kuberntes service 出现 502 问题排查
    应用应用容器化部署最佳实践
    监控系统设计
    kubernetes events 事件机制源码分析
    golang gc 原理和内存分配
    golang 使用 websocket 实现后台消息分组推送
    kubeadm 创建的 k8s 集群的升级
    在 kubernetes pod 中构建 docker image
  • 原文地址:https://www.cnblogs.com/LadyLex/p/7279150.html
Copyright © 2020-2023  润新知