• BZOJ3772: 精神污染


    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
    做过接水果这道题就简单了。
    设A的两端点为x,y,B的两端点为u,v。

    考虑一条路径A被另一条路径B包含的条件是:

    当x=y时,u和v有一个应在x的子树中,另一个应在x的子树外或等于x。

    当x、y构成了祖先关系时,设y为祖先、z为x到y路径上倒数第二个点,则u和v有一个应在x的子树中,另一个不在z的子树中。

    当x、y不构成祖先关系时,则u和v有一个应在x的子树中,另一个在y的子树中。

    那么一条路径可以变成至多2个矩形和一个点。

    扫描线+树状数组计算一下有多少点在矩形中就可以了。

    #include<cstdio>
    #include<cctype>
    #include<queue>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #define rep(i,s,t) for(int i=s;i<=t;i++)
    #define dwn(i,s,t) for(int i=s;i>=t;i--)
    #define ren for(int i=first[x];i;i=next[i])
    using namespace std;
    const int BufferSize=1<<16;
    char buffer[BufferSize],*head,*tail;
    inline char Getchar() {
        if(head==tail) {
            int l=fread(buffer,1,BufferSize,stdin);
            tail=(head=buffer)+l;
        }
        return *head++;
    }
    inline int read() {
        int x=0,f=1;char c=Getchar();
        for(;!isdigit(c);c=Getchar()) if(c=='-') f=-1;
        for(;isdigit(c);c=Getchar()) x=x*10+c-'0';
        return x*f;
    }
    typedef long long ll;
    const int maxn=100010;
    int n,m,e,first[maxn],next[maxn<<1],to[maxn<<1];
    void AddEdge(int u,int v) {
        to[++e]=v;next[e]=first[u];first[u]=e;
        to[++e]=u;next[e]=first[v];first[v]=e;
    }
    int anc[maxn][20],dep[maxn],st[maxn],en[maxn],ToT;
    void dfs(int x,int fa) {
        anc[x][0]=fa;rep(i,1,19) anc[x][i]=anc[anc[x][i-1]][i-1];
        dep[x]=dep[fa]+1;st[x]=++ToT;
        ren if(to[i]!=fa) dfs(to[i],x);
        en[x]=ToT;
    }
    int swim(int x,int k) {
        rep(i,0,19) if(k>>i&1) x=anc[x][i];
        return x;
    }
    struct Rect {
        int x,l,r,val;
        bool operator < (const Rect& ths) const {return x<ths.x;}
    }A[maxn<<2];
    struct Point {
        int x,y;
        bool operator < (const Point& ths) const {return x<ths.x||(x==ths.x&&y<ths.y);}
    }B[maxn];
    int N,M;
    void AddRect(int x,int y,int l,int r) {
        if(x>y||l>r) return;
        if(x<l) swap(x,l),swap(y,r);
        A[++N]=(Rect){x,l,r,1};A[++N]=(Rect){y+1,l,r,-1};
    }
    void AddPoint(int x,int y) {
        if(x<y) swap(x,y);
        B[++M]=(Point){x,y};
    }
    int sumv[maxn];
    int query(int x) {int res=0;for(;x;x-=x&-x) res+=sumv[x];return res;}
    void add(int x,int v) {for(;x<=n;x+=x&-x) sumv[x]+=v;}
    ll ans;
    ll gcd(ll a,ll b) {return !b?a:gcd(b,a%b);}
    int main() {
        n=read();m=read();
        rep(i,2,n) AddEdge(read(),read());
        dfs(1,0);
        rep(i,1,m) {
            int u=read(),v=read();AddPoint(st[u],st[v]);
            if(dep[u]<dep[v]) swap(u,v);
            if(u==v) AddRect(st[u],en[u],1,st[u]),AddRect(st[u],en[u],en[u]+1,n);
            else if(st[u]>=st[v]&&st[u]<=en[v]) {
                v=swim(u,dep[u]-dep[v]-1);
                AddRect(st[u],en[u],1,st[v]-1);
                AddRect(st[u],en[u],en[v]+1,n);
            }
            else AddRect(st[u],en[u],st[v],en[v]);
        }
        sort(A+1,A+N+1);sort(B+1,B+M+1);int j=1;
        rep(i,1,M) {
            while(j<=N&&A[j].x<=B[i].x) add(A[j].l,A[j].val),add(A[j].r+1,-A[j].val),j++;
            ans+=query(B[i].y);
        }
        rep(i,1,M) {
            int j=i;
            while(j<=M&&B[j].x==B[i].x&&B[j].y==B[i].y) j++;j--;
            ans-=(ll)(j-i+1)*(j-i)/2;
            i=j;
        }
        ans-=m;ll ans2=(ll)m*(m-1)/2,c=gcd(ans,ans2);
        printf("%lld/%lld
    ",ans/c,ans2/c);
        return 0;
    }
    View Code
  • 相关阅读:
    红楼【建筑位置】
    红楼【人物关系】
    jenkins【shared-libraries】
    linux 安装mysql8.0 tar.xz
    MySQL 输入字符串对日期进行模糊查询
    解决kali linux 和 win10 双系统时间不一致问题
    linux idea桌面图标
    linux卸载openjdk11
    tar.xz解压
    pandas模块高性能使用方法总结
  • 原文地址:https://www.cnblogs.com/wzj-is-a-juruo/p/5236143.html
Copyright © 2020-2023  润新知