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

精神污染

Time Limit: 10 Sec  Memory Limit: 64 MB
Submit: 637  Solved: 177
[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

所求的概率,以最简分数形式输出。

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

题解:

  将每个询问的点,按照dfs序的顺序,建立主席树

  每棵线段树的版本是其祖先的版本加上询问中在其节点上的,

  比如询问是x,y,那么建树在建到x的时候,将y加入当前线段树

  在y的in中加1,out中减1,in表示进入的dfs序,out表示出来的dfs序

  这个有什么用呢。

  

  对于询问x,y,f表示其lca,就是询问x和y的树中

  

  比如统计两个红点的答案,分别为x,y,f为lca,

  所以答案+x,y,f,fa[f]上询问in[f],in[x]

      +x,y,f,fa[f]上询问in[f],in[y]

      -x,y,f,fa[f]上询问in[f],in[f]

      -1减去自己

  即可。

  题目给的是没有相同的路径的。

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<set>
  5 #include<vector>
  6 #include<algorithm>
  7 #include<cmath>
  8
  9 #define ll long long
 10 #define N 100007
 11 using namespace std;
 12 inline int read()
 13 {
 14     int x=0,f=1;char ch=getchar();
 15     while(ch>‘9‘||ch<‘0‘){if (ch==‘-‘) f=-1;ch=getchar();}
 16     while(ch<=‘9‘&&ch>=‘0‘){x=(x<<3)+(x<<1)+ch-‘0‘;ch=getchar();}
 17     return x*f;
 18 }
 19
 20 int n,m,ind,sz;
 21 ll fz,fm;
 22 int ls[N*40],rs[N*41],sum[N*40];
 23 int deep[N],root[N*2],in[N],out[N];
 24 int fa[N][17],ci[20];
 25 vector<int>a[N];
 26 int cnt,hed[N],nxt[N*2],rea[N*2];
 27 struct query
 28 {
 29     int x,y;
 30 }q[N];
 31 bool operator<(query a,query b)
 32 {
 33     if(a.x==b.x)return a.y<b.y;
 34     else return a.x<b.x;
 35 }
 36
 37 ll gcd(ll a,ll b){return !b?a:gcd(b,a%b);}
 38 void add(int u,int v)
 39 {
 40     nxt[++cnt]=hed[u];
 41     hed[u]=cnt;
 42     rea[cnt]=v;
 43 }
 44 void dfs(int x)
 45 {
 46     for(int i=1;(1<<i)<=deep[x];i++)
 47         fa[x][i]=fa[fa[x][i-1]][i-1];
 48     in[x]=++ind;
 49     for(int i=hed[x];i!=-1;i=nxt[i])
 50     {
 51         int v=rea[i];
 52         if(v!=fa[x][0])
 53         {
 54             fa[v][0]=x;
 55             deep[v]=deep[x]+1;
 56             dfs(v);
 57         }
 58     }
 59     out[x]=++ind;
 60 }
 61 inline void update(int p){sum[p]=sum[ls[p]]+sum[rs[p]];}
 62 /*void ins(int yl,int &xz,int l,int r,int pos,int val)
 63 {
 64     xz=++sz,ls[xz]=ls[yl],rs[xz]=rs[yl];
 65     if(l==r)
 66     {
 67         sum[xz]=sum[yl]+val;
 68         return;
 69     }
 70     int mid=(l+r)>>1;
 71     if(pos<=mid) ins(ls[yl],ls[xz],l,mid,pos,val);
 72     else ins(rs[yl],rs[xz],mid+1,r,pos,val);
 73     update(xz);
 74 }*/
 75
 76 int insert(int x,int l,int r,int pos,int val)
 77 {
 78     int t=++sz;
 79     ls[t]=ls[x];rs[t]=rs[x];
 80     if(l==r){sum[t]=sum[x]+val;return t;}
 81     int mid=(l+r)>>1;
 82     if(pos<=mid)ls[t]=insert(ls[t],l,mid,pos,val);
 83     else rs[t]=insert(rs[t],mid+1,r,pos,val);
 84     sum[t]=sum[ls[t]]+sum[rs[t]];
 85     return t;
 86 }
 87 int query(int p1,int p2,int p3,int p4,int l,int r,int st,int ed)
 88 {
 89     int mid=(l+r)>>1;
 90     if(l==st&&r==ed) {return sum[p1]+sum[p2]-sum[p3]-sum[p4];}
 91     if(ed<=mid) return query(ls[p1],ls[p2],ls[p3],ls[p4],l,mid,st,ed);
 92     else if(st>mid) return query(rs[p1],rs[p2],rs[p3],rs[p4],mid+1,r,st,ed);
 93     else return query(ls[p1],ls[p2],ls[p3],ls[p4],l,mid,st,mid)+query(rs[p1],rs[p2],rs[p3],rs[p4],mid+1,r,mid+1,ed);
 94 }
 95 /*
 96 void build(int x)
 97 {
 98     root[0]=root[fa[x][0]];
 99     for(int i=0;i<a[x].size();i++)
100     {
101         ins(root[0],root[N-1],1,ind,in[a[x][i]],1);
102         ins(root[N-1],root[x],1,ind,out[a[x][i]],-1);
103     }
104     for(int i=hed[x];i!=-1;i=nxt[i])
105     {
106         int v=rea[i];
107         if(v!=fa[x][0]) build(v);
108     }
109 }*/
110
111 void build(int x)
112 {
113     root[x]=root[fa[x][0]];
114     for(int i=0;i<a[x].size();i++)
115     {
116         root[x]=insert(root[x],1,ind,in[a[x][i]],1);
117         root[x]=insert(root[x],1,ind,out[a[x][i]],-1);
118     }
119     for(int i=hed[x];i!=-1;i=nxt[i])
120     {
121         int v=rea[i];
122         if(v!=fa[x][0])
123             build(v);
124     }
125 }
126 int lca(int a,int b)
127 {
128     if (deep[a]<deep[b]) swap(a,b);
129     int i;for (i=0;(1<<i)<=deep[a];i++);i--;
130     for (int j=i;j>=0;j--)
131         if (deep[a]-(1<<j)>=deep[b]) a=fa[a][j];
132     if (a==b) return a;
133     for (int j=i;j>=0;j--)
134         if (fa[a][j]!=fa[b][j]) a=fa[a][j],b=fa[b][j];
135     return fa[a][0];
136 }
137 void solve()
138 {
139     for(int i=1;i<=m;i++)
140     {
141         int x=q[i].x,y=q[i].y,f=lca(x,y);
142         fz+=query(root[x],root[y],root[f],root[fa[f][0]],1,ind,in[f],in[x]);
143         fz+=query(root[x],root[y],root[f],root[fa[f][0]],1,ind,in[f],in[y]);
144         fz-=query(root[x],root[y],root[f],root[fa[f][0]],1,ind,in[f],in[f]);
145         fz--;
146     }
147 }
148 inline void init()
149 {
150     ci[0]=1;
151     for(int i=1;i<20;i++)ci[i]=ci[i-1]<<1;
152
153     memset(hed,-1,sizeof(hed));
154     n=read();m=read();
155     for(int i=1;i<n;i++)
156     {
157         int u=read(),v=read();
158         add(u,v),add(v,u);//加边,没什么问题。
159     }
160     for(int i=1;i<=m;i++)
161     {
162         int x=read(),y=read();
163         a[x].push_back(y);//在边的起点放入另外一个端点。
164         q[i].x=x,q[i].y=y;
165     }
166     sort(q+1,q+m+1);//q按照x为第一关键字来排序。
167 }
168 int main()
169 {
170     freopen("fzy.in","r",stdin);
171     freopen("fzy.out","w",stdout);
172
173     init(),dfs(1),build(1),solve();
174
175     fm=(ll)m*(m-1)/2;
176     ll t=gcd(fz,fm);
177     fz/=t;fm/=t;
178     printf("%lld/%lld",fz,fm);
179 }
时间: 2024-10-23 16:46:43

bzoj 3772 精神污染 主席树+dfs序的相关文章

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

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

BZOJ 2809: [Apio2012]dispatching [主席树 DFS序]

传送门 题意:查询树上根节点值*子树中权值和$\le m$的最大数量 最大值是多少 求$DFS$序,然后变成区间中和$\le m$最多有几个元素,建主席树,然后权值线段树上二分就行了 $WA$:又把边表开小了..... 好吧我$zz$了有根树加无向边干什么.... #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #de

51 nod 1681 公共祖先 (主席树+dfs序)

1681 公共祖先 基准时间限制:1 秒 空间限制:131072 KB 分值: 80 难度:5级算法题 有一个庞大的家族,共n人.已知这n个人的祖辈关系正好形成树形结构(即父亲向儿子连边). 在另一个未知的平行宇宙,这n人的祖辈关系仍然是树形结构,但他们相互之间的关系却完全不同了,原来的祖先可能变成了后代,后代变成的同辈…… 两个人的亲密度定义为在这两个平行宇宙有多少人一直是他们的公共祖先. 整个家族的亲密度定义为任意两个人亲密度的总和. Input 第一行一个数n(1<=n<=100000)

【BZOJ1803】Spoj1487 Query on a tree III 主席树+DFS序

[BZOJ1803]Spoj1487 Query on a tree III Description You are given a node-labeled rooted tree with n nodes. Define the query (x, k): Find the node whose label is k-th largest in the subtree of the node x. Assume no two nodes have the same labels. Input

【BZOJ 3772】精神污染 主席树+欧拉序

这道题的内存-------真·精神污染---.. 这道题的思路很明了,我们就是要找每一个路径包含了多少其他路径那么就是找,有多少路径的左右端点都在这条路径上,对于每一条路径,我们随便选定一个端点作为第一关键字,另一个作为第二关键字,于是就有了两维限制,按照主席树的一般思路,我们把建树顺序作为一维,然后在里面维护另一维,那么我们在外面限制第一关键字,就是在树上建主席树,查询减LCA,在里面的话我们把每个点作为第一关键字对应的第二关键字,放入主席树,而主席树维护的是欧拉序区间,所以我们每次查询只用查

P2633|主席树+dfs序+树链剖分求lca+离散化

不知道为什么会RE.. 待补 思路:链上求u和v两点路径第k小利用lca就转变为了 U+V-LCA-FA(LCA) 上的第k小,这因为每个点的主席树的root是从其父转移来的.可以用树链剖分求lca:在dfs序上建立主席树将树上问题转变为区间问题,询问的时候用主席树求区间k小值. 终于能写出这种题了,开心! #include<bits/stdc++.h> using namespace std; const int maxn = 1e5+100; int n,m,e = 1,num,ans=0

P3899|主席树+dfs序

理解题意后分两种情况: 1.b在a的上方: min(dep[p]-1,k)*(ll)siz[p] 因为(p点上方肯定有父亲结点b,我们不用管b是谁) 2.b在a的下方: (dep(p)+1 ~ dep(p)+k矩形框内的所有点子树个数和 所以思路:主席树维护同一深度下的各个结点子树个数和:下标是深度,权值维护的是子树个数和:在dfs序in和out时间戳上建立主席树,把树上问题转变为区间序列问题,利用dfs序时间戳的性质(子树编号在入时间戳和出时间戳的区间内),查询以p为根子树:所以问题就转变为了

BZOJ_1803_Spoj1487 Query on a tree III_主席树+dfs序

BZOJ_1803_Spoj1487 Query on a tree III_主席树 Description You are given a node-labeled rooted tree with n nodes. Define the query (x, k): Find the node whose label is k-th largest in the subtree of the node x. Assume no two nodes have the same labels. I

Tsinsen A1505. 树(张闻涛) 倍增LCA,可持久化线段树,DFS序

题目:http://www.tsinsen.com/A1505 A1505. 树(张闻涛) 时间限制:1.0s   内存限制:512.0MB 总提交次数:196   AC次数:65   平均分:58.62 将本题分享到: 查看未格式化的试题   提交   试题讨论 试题来源 2013中国国家集训队第二次作业 问题描述 给定一棵N个节点的树,每个点有一个权值,有M个询问(a,b,c)若a 为1,回答b到c路径上的最小权值,若a为2,回答b到c路径上的最大权值,若a为3,回答b到c路径上的所有权值的