zoukankan      html  css  js  c++  java
  • 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 }
  • 相关阅读:
    硬盘任性丢数据,但分布式存储一定可靠吗?
    Service的基本组成
    固定cell.imageView.image的大小
    剪贴板服务
    取得正在运行的Activity
    取得正在运行的服务
    C#.NET学习笔记1---C#.NET简介
    取得手机的网络信息
    四、cocos2dx动画Animation介绍
    C#.NET学习笔记2---C#.第一个C#程序
  • 原文地址:https://www.cnblogs.com/fengzhiyuan/p/8082507.html
Copyright © 2011-2022 走看看