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 }