bzoj 3772 :精神污染 线段树+打标记 or 主席树
Posted SD_le
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj 3772 :精神污染 线段树+打标记 or 主席树相关的知识,希望对你有一定的参考价值。
3772: 精神污染
Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 315 Solved: 87
[Submit][Status][Discuss]
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
所求的概率,以最简分数形式输出。
答案很容易就可以看出来是 Σ(1<=i<=m)包含第i条路径的路径数/c(m,2)。
那我们考虑每一条路径被多少条路径包含。
一条路径A->B有三种情况,一是A和B分属LCA的两颗子树里,二是A或B是LCA,三是A=B.
对于第一种情况我们查A的子树中有多少询问一端在A的子树中,一端在B的子树中。
我们可以类似noip2016 day1t2的思路在每个询问的两个端点打上标记,在A点存上B,在B点存上A,统计答案时我们就只在A点查。
动态维护一颗线段树,树的下标为dfs序,按当前遍历到的所有标记所指向节点的dfs序存进去,统计区间。
当我们dfs到A点时,对于A的每一个询问,先把答案减去线段树中[st[B],ed[B]]]这个区间的和,然后把A点的标记放进树里,dfs子树,再把答案加上[st[B],ed[B]]]这个区间的和。
相当于去除了子树之外的影响。
第二种情况差不多,只不过询问区间不一样。
第三种需要特判,不多说了。
记得把初始答案设为-m,因为这样计算会认为自己包含自己。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<vector> 6 #define LL long long 7 #define ls x*2,l,mid 8 #define rs x*2+1,mid+1,r 9 #define N 200005 10 using namespace std; 11 LL gcd(LL a,LL b) 12 { 13 if(!b)return a; 14 return gcd(b,a%b); 15 } 16 int n,m; 17 int head[N],ver[N*2],nxt[N*2],tot; 18 void add(int a,int b) 19 { 20 tot++;nxt[tot]=head[a];head[a]=tot;ver[tot]=b;return ; 21 } 22 int dep[N],fa[N][20],dfn[N],z,ed[N]; 23 void dfs(int x,int f) 24 { 25 dfn[x]=++z; 26 for(int i=head[x];i;i=nxt[i]) 27 { 28 if(ver[i]==f)continue; 29 dep[ver[i]]=dep[x]+1; 30 fa[ver[i]][0]=x; 31 dfs(ver[i],x); 32 }ed[x]=z; 33 } 34 void yu() 35 { 36 for(int i=1;i<=17;i++) 37 { 38 for(int j=1;j<=n;j++) 39 { 40 fa[j][i]=fa[fa[j][i-1]][i-1]; 41 } 42 }return ; 43 } 44 int lca(int x,int y) 45 { 46 if(dep[x]<dep[y])swap(x,y); 47 for(int i=17;i>=0;i--) 48 { 49 if(dep[fa[x][i]]>=dep[y])x=fa[x][i]; 50 } 51 if(x==y)return x; 52 for(int i=17;i>=0;i--) 53 { 54 if(fa[x][i]!=fa[y][i]) 55 { 56 x=fa[x][i];y=fa[y][i]; 57 } 58 } 59 return fa[x][0]; 60 } 61 int a[N*8]; 62 void add(int x,int l,int r,int pos,int z) 63 { 64 if(l==r) 65 { 66 a[x]+=z; 67 return ; 68 } 69 int mid=(l+r)>>1; 70 if(pos<=mid)add(ls,pos,z); 71 else add(rs,pos,z); 72 a[x]=a[x*2]+a[x*2+1]; 73 } 74 int qur(int x,int l,int r,int ll,int rr) 75 { 76 if(ll>rr)return 0; 77 if(ll<=l&&rr>=r) 78 { 79 return a[x]; 80 } 81 int mid=(l+r)>>1; 82 if(ll>mid)return qur(rs,ll,rr); 83 if(rr<=mid)return qur(ls,ll,rr); 84 return qur(rs,ll,rr)+qur(ls,ll,rr); 85 } 86 struct qr 87 { 88 int x,y; 89 }q[N]; 90 struct node 91 { 92 int op,y; 93 node(int xx,int yy) 94 { 95 op=xx;y=yy; 96 } 97 }; 98 int faa(int x,int y) 99 { 100 for(int i=17;i>=0;i--) 101 { 102 if(dep[fa[x][i]]>dep[y])x=fa[x][i]; 103 } 104 return x; 105 } 106 vector<node>lazy[N]; 107 LL ans; 108 int sb[N]; 109 void dp(int x,int f) 110 { 111 for(int i=0;i<lazy[x].size();i++) 112 { 113 if(!lazy[x][i].op)continue; 114 if(lazy[x][i].op==1) 115 { 116 ans-=qur(1,1,n,dfn[lazy[x][i].y],ed[lazy[x][i].y]); 117 } 118 else 119 { 120 int yy=lazy[x][i].y; 121 int now=faa(x,yy); 122 ans-=qur(1,1,n,1,dfn[now]-1)+qur(1,1,n,ed[now]+1,n); 123 if(x==yy) 124 { 125 ans-=qur(1,1,n,dfn[x],dfn[x]); 126 } 127 } 128 } 129 for(int i=0;i<lazy[x].size();i++) 130 { 131 add(1,1,n,dfn[lazy[x][i].y],1); 132 if(lazy[x][i].op==1) 133 { 134 int uu=lca(x,lazy[x][i].y); 135 sb[uu]++; 136 } 137 } 138 for(int i=head[x];i;i=nxt[i]) 139 { 140 if(ver[i]==f)continue; 141 dp(ver[i],x); 142 } 143 for(int i=0;i<lazy[x].size();i++) 144 { 145 if(!lazy[x][i].op)continue; 146 if(lazy[x][i].op==1) 147 { 148 ans+=qur(1,1,n,dfn[lazy[x][i].y],ed[lazy[x][i].y]); 149 } 150 else 151 { 152 int yy=lazy[x][i].y; 153 int now=faa(x,yy); 154 if(x==yy) 155 { 156 ans+=qur(1,1,n,dfn[x],dfn[x]); 157 ans+=sb[x]; 158 } 159 ans+=qur(1,1,n,1,dfn[now]-1)+qur(1,1,n,ed[now]+1,n); 160 } 161 } 162 } 163 int main() 164 { 165 scanf("%d%d",&n,&m); 166 int t1,t2; 167 for(int i=1;i<n;i++) 168 { 169 scanf("%d%d",&t1,&t2); 170 add(t1,t2);add(t2,t1); 171 } 172 ans=-m; 173 dep[1]=1; 174 dfs(1,-1); 175 yu(); 176 for(int i=1;i<=m;i++) 177 { 178 scanf("%d%d",&q[i].x,&q[i].y); 179 int tmp=lca(q[i].x,q[i].y); 180 if(tmp==q[i].x) 181 { 182 lazy[q[i].y].push_back(node(2,q[i].x)); 183 if(q[i].x!=q[i].y)lazy[q[i].x].push_back(node(0,q[i].y)); 184 } 185 else if(tmp==q[i].y) 186 { 187 lazy[q[i].y].push_back(node(0,q[i].x)); 188 lazy[q[i].x].push_back(node(2,q[i].y)); 189 } 190 else 191 { 192 lazy[q[i].x].push_back(node(1,q[i].y)); 193 lazy[q[i].y].push_back(node(0,q[i].x)); 194 } 195 } 196 dp(1,-1); 197 LL tt=(LL)m*(m-1)/2; 198 LL oo=gcd(tt,ans); 199 printf("%lld/%lld\n",ans/oo,tt/oo); 200 return 0; 201 }
以上是关于bzoj 3772 :精神污染 线段树+打标记 or 主席树的主要内容,如果未能解决你的问题,请参考以下文章