bzoj 3772 :精神污染 线段树+打标记 or 主席树

3772: 精神污染

Time Limit: 10 Sec  Memory Limit: 64 MB
Submit: 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 }
时间: 2024-09-30 18:43:02

bzoj 3772 :精神污染 线段树+打标记 or 主席树的相关文章

bzoj 3772 精神污染 主席树+dfs序

精神污染 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 637  Solved: 177[Submit][Status][Discuss] Description 兵库县位于日本列岛的中央位置,北临日本海,南面濑户内海直通太平洋,中央部位是森林和山地,与拥有关西机场的大阪府比邻而居,是关西地区面积最大的县,是集经济和文化于一体的一大地区,是日本西部门户,海陆空交通设施发达.濑户内海沿岸气候温暖,多晴天,有日本少见的贸易良港神户港所在的神户市和曾是豪

[poj2104]可持久化线段树入门题(主席树)

解题关键:离线求区间第k小,主席树的经典裸题: 对主席树的理解:主席树维护的是一段序列中某个数字出现的次数,所以需要预先离散化,最好使用vector的erase和unique函数,很方便:如果求整段序列的第k小,我们会想到离散化二分和线段树的做法, 而主席树只是保存了序列的前缀和,排序之后,对序列的前缀分别做线段树,具有差分的性质,因此可以求任意区间的第k小,如果主席树维护索引,只需要求出某个数字在主席树中的位置,即为sort之后v中的索引:若要求第k大,建树时反向排序即可 1 #include

BZOJ 3196 Tyvj 1730 二逼平衡树 ——树状数组套主席树

[题目分析] 听说是树套树.(雾) 怒写树状数组套主席树,然后就Rank1了.23333 单点修改,区间查询+k大数查询=树状数组套主席树. [代码] #include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <set> #include <map> #include <string> #include <alg

[BZOJ 3196] 二逼平衡树 树状数组套主席树

3196: Tyvj 1730 二逼平衡树 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 3357  Solved: 1326[Submit][Status][Discuss] Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:1.查询k在区间内的排名2.查询区间内排名为k的值3.修改某一位值上的数值4.查询k在区间内的前驱(前驱定义为小于x,且最大的数)5.查询k在区间内的后继(后继定义为

【BZOJ1901】Dynamic Rankings,树状数组套主席树

Time:2016.05.09 Author:xiaoyimi 转载注明出处谢谢 传送门(权限) 题面 1901: Zju2112 Dynamic Rankings Time Limit: 10 Sec Memory Limit: 128 MB Submit: 6678 Solved: 2777 [Submit][Status][Discuss] Description 给定一个含有n个数的序列a[1],a[2],a[3]--a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a

[COGS257]动态排名系统 树状数组套主席树

257. 动态排名系统 时间限制:5 s   内存限制:512 MB [问题描述]给定一个长度为N的已知序列A[i](1<=i<=N),要求维护这个序列,能够支持以下两种操作:1.查询A[i],A[i+1],A[i+2],...,A[j](1<=i<=j<=N)中,升序排列后排名第k的数.2.修改A[i]的值为j.所谓排名第k,指一些数按照升序排列后,第k位的数.例如序列{6,1,9,6,6},排名第3的数是6,排名第5的数是9.[输入格式]第一行包含一个整数D(0<=

关于树状数组套主席树的一些博客

哇仿佛磕了几百年啊; 废话不多说,以下是帮助很大的一些blog: ZOJ 2112 Dynamic Rankings (动态第k大,树状数组套主席树) 主席树全纪录(这个很好) 主席树乱讲(没啥关系,不过有些题目可以刷??) 随笔分类 - 数据结构---主席树(同上) 原文地址:https://www.cnblogs.com/wwtt/p/10099695.html

BZOJ 3626: [LNOI2014]LCA [树链剖分 离线|主席树]

3626: [LNOI2014]LCA Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2050  Solved: 817[Submit][Status][Discuss] Description 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1.设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先.有q次询问,每次询问给出l r z,求sigma_{l<=i<=r}dep[LC

BZOJ 1146: [CTSC2008]网络管理Network( 树链剖分 + 树状数组套主席树 )

树链剖分完就成了一道主席树裸题了, 每次树链剖分找出相应区间然后用BIT+(可持久化)权值线段树就可以完成计数. 但是空间问题很严重....在修改时不必要的就不要新建, 直接修改原来的..详见代码. 时间复杂度O(N*log^3(N)) ---------------------------------------------------------------------------- #include<cstdio> #include<cstring> #include<