1. 程式人生 > >BZOJ_3772_精神汙染_主席樹

BZOJ_3772_精神汙染_主席樹

string memset eof 表示 不同的 IT add 完全 維護

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
orz popoqqq https://blog.csdn.net/popoqqq/article/details/43122821 寫完之後發現有更簡單的方法。。。 方法一:離線樹狀數組 首先有兩種路徑,1字形和V字形。 對於1字型的路徑,包含它的路徑兩端一定在鏈頂的兒子的子樹外和鏈底的子樹內,在dfs序上就劃出了兩個線段。 對於V字形的路徑,被它包含的路徑兩端一定在兩個端點的子樹內,這也是兩個線段。 把每條路經的端點在dfs序中的位置看成二維平面上的點,然後離線樹狀數組二維數點即可。 方法二:出棧入棧序+主席樹 把詢問掛鏈(x,y),然後每個點維護根到這個點路徑的信息。 在x這顆線段樹上把y的入棧位置+1,出棧位置-1。 然後把詢問分成x->lca,lca->y,每次分別查詢x到y路徑上dfn[lca]到dfn[x],dfn[lca]到dfn[y]之間的和,其中dfn[x]表示x在dfs序中的位置。 分析一下,對於其中包含的路徑(z,w),z這個點一定在x到y路徑上,故z剛剛做出的修改會在x到y這段路經上體現。 那麽我們就只需要找w,由於我把入棧位置+1出棧位置-1,相當於差分實現區間加,因此查詢時會查到w。 代碼(方法二):
#include <cstdio>
#include <string.h>
#include <algorithm>
using namespace std;
#define N 100050
typedef long long ll;
int head[N],to[N<<1],nxt[N<<1],cnt,n,m,root[N],maxn;
int fa[N],top[N],siz[N],son[N],dep[N],dfn[N],S[N],out[N],t[N*39],tot,ls[N*39],rs[N*39];
inline void add(int u,int v) {
    to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt;
}
void insert(int &y,int x,int l,int r,int v,int c) {
    y=++tot; t[y]=t[x]+c;
    if(l==r) return ;
    int mid=(l+r)>>1;
    if(v<=mid) rs[y]=rs[x],insert(ls[y],ls[x],l,mid,v,c);
    else ls[y]=ls[x],insert(rs[y],rs[x],mid+1,r,v,c);
}
int query(int a,int b,int c,int d,int l,int r,int x,int y) {
    if(x<=l&&y>=r) return t[a]+t[b]-t[c]-t[d];
    int mid=(l+r)>>1,re=0;
    if(x<=mid) re+=query(ls[a],ls[b],ls[c],ls[d],l,mid,x,y);
    if(y>mid) re+=query(rs[a],rs[b],rs[c],rs[d],mid+1,r,x,y);
    return re;
}
void dfs1(int x,int y) {
    S[++S[0]]=x; dfn[x]=++maxn;
    int i; dep[x]=dep[y]+1; fa[x]=y; siz[x]=1;
    for(i=head[x];i;i=nxt[i]) if(to[i]!=y) {
        dfs1(to[i],x); siz[x]+=siz[to[i]];
        if(siz[to[i]]>siz[son[x]]) son[x]=to[i];
    }
    out[x]=++maxn;
}
void dfs2(int x,int t) {
    top[x]=t; int i; if(son[x]) dfs2(son[x],t);
    for(i=head[x];i;i=nxt[i]) if(to[i]!=fa[x]&&to[i]!=son[x]) dfs2(to[i],to[i]);
}
int lca(int x,int y) {
    while(top[x]!=top[y]) {
        if(dep[top[x]]>dep[top[y]]) swap(x,y);
        y=fa[top[y]];
    }
    return dep[x]<dep[y]?x:y;
}
ll gcd(ll x,ll y) {
    return y?gcd(y,x%y):x;
}
int main() {
    scanf("%d%d",&n,&m);
    int i,x,y,j;
    for(i=1;i<n;i++) {
        scanf("%d%d",&x,&y);
        add(x,y); add(y,x);
    }
    dfs1(1,0);
    dfs2(1,1);
    memset(head,0,sizeof(head)); cnt=0;
    for(i=1;i<=m;i++) {
        scanf("%d%d",&x,&y);
        add(x,y);
    }
    for(j=1;j<=n;j++) {
        x=S[j];
        root[x]=root[fa[x]];
        for(i=head[x];i;i=nxt[i]) {
            y=to[i];
            insert(root[x],root[x],1,maxn,dfn[y],1);
            insert(root[x],root[x],1,maxn,out[y],-1);
        }
    }
    ll ans=0,dev=1ll*m*(m-1)/2;;
    for(x=1;x<=n;x++) {
        for(i=head[x];i;i=nxt[i]) {
            y=to[i];
            int l=lca(x,y);
            ans+=query(root[x],root[y],root[l],root[fa[l]],1,maxn,dfn[l],dfn[x]);
            ans+=query(root[x],root[y],root[l],root[fa[l]],1,maxn,dfn[l],dfn[y]);
            ans-=query(root[x],root[y],root[l],root[fa[l]],1,maxn,dfn[l],dfn[l]);
            ans--;
        }
    }
    ll tmp=gcd(ans,dev);
    printf("%lld/%lld\n",ans/tmp,dev/tmp);
}

BZOJ_3772_精神汙染_主席樹