Bzoj 3772: 精神污染

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

 

这道题...真是思(jing)路(shen)好(wu)题(ran)..!可以先求出所有路径包含几条路径的和,然后再除组合数。看题解想了好久才反应过来题解在干什么...首先dfs跑出欧拉序,记录每个点的in,out,然后对于一条路径(x,y),在点x上挂链。第二次dfs的时候每个点维护主席树,在in[y]处+1,在out[y]处-1。然后查询就是枚举每条路径(a,b),看看它能够覆盖几条线段,所以下面根节点标号的贡献是:a+b-lca-fa[lca],就是求出x在这条路径上的主席树。然后在这上面查询in[lca]到in[a],in[lca]到in[b],因为lca被计算了两次,所以减掉,还要注意每个线段还算了自己一次,再减去1。最后和C(m,2)求个gcd就行了...貌似还卡空间?

下面代码:

  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<cstring>
  4 #include<iostream>
  5 #include<vector>
  6 using namespace std;
  7 struct node{
  8     int lson,rson,val;
  9 }tree[4000010];
 10 int head[100010],nxt[200010],whr[200010],deep[100010],bz[100010][17],in[100010],out[100010],root[100010],cnt=1;
 11 int aa[100010],bb[100010],n,st,ed,val;
 12 vector<int>vec[100010];
 13 long long gcd(long long a,long long b){
 14     if(b==0ll) return a;
 15     return gcd(b,a%b);
 16 }
 17 void add(int a,int b){
 18     nxt[cnt]=head[a];
 19     whr[cnt]=b;
 20     head[a]=cnt++;
 21     return;
 22 }
 23 void dfs1(int pos,int las){
 24     in[pos]=++cnt;
 25     bz[pos][0]=las;
 26     deep[pos]=deep[las]+1;
 27     int i,t;
 28     for(i=1;i<=16;i++) bz[pos][i]=bz[bz[pos][i-1]][i-1];
 29     for(i=head[pos];i;i=nxt[i]){
 30         t=whr[i];
 31         if(t!=las) dfs1(t,pos);
 32     }
 33     out[pos]=++cnt;
 34     return;
 35 }
 36 void insert(int l,int r,int pos,int las){
 37     tree[pos].val=tree[las].val+val;
 38     if(l==r) return;
 39     int mid=(l+r)/2;
 40     if(st<=mid){
 41         tree[pos].lson=++cnt;
 42         tree[pos].rson=tree[las].rson;
 43         insert(l,mid,tree[pos].lson,tree[las].lson);
 44     }
 45     else{
 46         tree[pos].rson=++cnt;
 47         tree[pos].lson=tree[las].lson;
 48         insert(mid+1,r,tree[pos].rson,tree[las].rson);
 49     }
 50     return;
 51 }
 52 void dfs2(int pos,int las){
 53     if(vec[pos].size()==0) root[pos]=root[las];
 54     for(unsigned i=0,qian=root[las];i<vec[pos].size();i++){
 55         st=in[vec[pos][i]],val=1;
 56         root[pos]=++cnt;
 57         insert(1,(n<<1),root[pos],qian);
 58         qian=root[pos];
 59         st=out[vec[pos][i]],val=-1;
 60         root[pos]=++cnt;
 61         insert(1,(n<<1),root[pos],qian);
 62         qian=root[pos];
 63     }
 64     for(int i=head[pos];i;i=nxt[i]) if(whr[i]!=las) dfs2(whr[i],pos);
 65     return;
 66 }
 67 int getlca(int a,int b){
 68     int i;
 69     if(deep[a]<deep[b]) swap(a,b);
 70     for(i=16;i>=0;i--) if(deep[bz[a][i]]>=deep[b]) a=bz[a][i];
 71     if(a==b) return a;
 72     for(i=16;i>=0;i--) if(bz[a][i]!=bz[b][i]) a=bz[a][i],b=bz[b][i];
 73     return bz[a][0];
 74 }
 75 int find(int l,int r,int r1,int r2,int r3,int r4){
 76     if(st<=l&&r<=ed) return tree[r1].val+tree[r2].val-tree[r3].val-tree[r4].val;
 77     int mid=(l+r)/2;
 78     if(ed<=mid) return find(l,mid,tree[r1].lson,tree[r2].lson,tree[r3].lson,tree[r4].lson);
 79     if(mid<st) return find(mid+1,r,tree[r1].rson,tree[r2].rson,tree[r3].rson,tree[r4].rson);
 80     return find(l,mid,tree[r1].lson,tree[r2].lson,tree[r3].lson,tree[r4].lson)+find(mid+1,r,tree[r1].rson,tree[r2].rson,tree[r3].rson,tree[r4].rson);
 81 }
 82 int main()
 83 {
 84     int m,i,a,b,lca;
 85     long long ans=0ll,zu,g;
 86     scanf("%d%d",&n,&m);
 87     for(i=1;i<n;i++){
 88         scanf("%d%d",&a,&b);
 89         add(a,b),add(b,a);
 90     }
 91     for(i=1;i<=m;i++){
 92         scanf("%d%d",&a,&b);
 93         aa[i]=a,bb[i]=b;
 94         vec[a].push_back(b);
 95     }
 96     cnt=0;dfs1(1,0);
 97     cnt=0;dfs2(1,0);
 98     for(i=1;i<=m;i++){
 99         a=aa[i],b=bb[i],lca=getlca(a,b);
100         st=in[lca],ed=in[a];
101         ans+=find(1,(n<<1),root[a],root[b],root[lca],root[bz[lca][0]]);
102         st=in[lca],ed=in[b];
103         ans+=find(1,(n<<1),root[a],root[b],root[lca],root[bz[lca][0]]);
104         st=ed=in[lca];
105         ans-=find(1,(n<<1),root[a],root[b],root[lca],root[bz[lca][0]]);
106         ans--;
107     }
108     zu=(long long)(m)*(long long)(m-1)/(long long)2;
109     g=gcd(ans,zu);
110     printf("%lld/%lld\n",ans/g,zu/g);
111     return 0;
112 }

 

posted @ 2018-02-25 21:29  PnCbf  阅读(148)  评论(0编辑  收藏  举报