zoukankan      html  css  js  c++  java
  • 【省选组】模拟gmoj3978. 寝室管理

    r 64 有一个好朋友,叫r 128 。r 128 是寄宿生,并且最近被老师叫过去当宿管了。宿
    管可不是一件很好做的工作,碰巧r 128 有一个工作上的问题想请r 64 帮忙解决。
    r 128 的寝室条件不是很好,所以没有很多钱来装修。n间寝室仅由n − 1条双向道
    路连接,而且任意两间寝室之间都可以互达。最近,r 128 被要求对一条路径上的所有
    寝室进行管理, 这条路径不会重复经过某个点或某条边。 但他不记得是哪条路径了。
    他只记得这条路径上有不少于k个寝室。于是,他想请r 64 帮忙数一下,有多少条这
    样的路径满足条件。
    嗯...还有一个问题。由于最近有一些熊孩子不准晚上讲话很不爽,他们决定修筑
    一条“情报通道”,如果通道建成,寝室就变成了一个n个点n条边的无向图。并且,
    经过“情报通道”的路径也是合法的。r 128 心想:通道建成之前,r 64 还有一个高效
    的算法帮我数路径条数,但是通道建成之后,他还有办法吗?对,r 64 手忙脚乱,根
    本数不清有多少条路径。于是他找到了你。

    这道题考场时脑瘫了,50分的暴力打了点分治。

    正解也是点分治,对于n=m的情况,可以将环上某一条边去掉,转化成一棵树,用点分治求答案。

    然后再单独考虑这个环的情况,可以从断边的一个端点开始扫,统计这个端点顺时针走到断边的答案,再将这个端点逆时针走到端点的答案加入到线段树中。

    这里偷一个大佬博客的图。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define N 300000
    #define ll long long
    using namespace std;
    ll n,m,len,i,j,x,y,q[N],size[N],sizen,root,mxs[N],tot,ans,num,a[N],bz[N],bzp[N],bzx,bzy;
    ll stk[N],top,hu[N],cnt,ls[N],bzf[N];
    struct edge{
        ll to,next;
    }e[N];
    struct node{
        ll sum;
    }f[N*10];
    void insert(ll x,ll y){
        tot++;
        e[tot].to=y;
        e[tot].next=q[x];
        q[x]=tot;
    }
    void getroot(ll x,ll father){
        ll i,y;
        size[x]=1;
        mxs[x]=0;
        for (i=q[x];i;i=e[i].next){
            y=e[i].to;
            if (x==bzx&&y==bzy||x==bzy&&y==bzx)
                continue;
            if (y!=father&&!bz[y]){
                getroot(y,x);
                size[x]+=size[y];
                mxs[x]=max(mxs[x],size[y]);
            }
        }
        mxs[x]=max(mxs[x],sizen-size[x]);
        if (mxs[x]<mxs[root])
            root=x;
    }
    void dfs1(ll x,ll ed,ll father,ll opt){
        a[++num]=ed;
        ll i,y;
        for (i=q[x];i;i=e[i].next){
            y=e[i].to;
            if (x==bzx&&y==bzy||x==bzy&&y==bzx)
                continue;
            if (y!=father&&bz[y]==0&&opt==1||y!=father&&opt==0&&bzf[y]==0)
                dfs1(y,ed+1,x,opt);
        }
    }
    ll getans(ll x,ll ed){
        num=0;
        dfs1(x,ed,0,1);
        ll l=1,r=num,sum=0;
        sort(a+1,a+num+1);
        while (true){
            while (l<=num&&a[l]+a[r]<len)
                l++;
            if (r<l)
                break;
            sum+=r-l;
            if (a[r]>=len)
                sum++;
            r--;
        }
        return sum;
    }
    void dfs(ll x){
        ans+=getans(x,0);
        ll i,y;
        bz[x]=1;
        for (i=q[x];i;i=e[i].next){
            y=e[i].to;
            if (x==bzx&&y==bzy||x==bzy&&y==bzx)
                continue;
            if (!bz[y]){
                ans-=getans(y,1);
                root=0;
                sizen=size[y];
                getroot(y,0);
                dfs(root);
            }
        }
    }
    void dfsp(ll x,ll father){
        ll i,y;
        if (bzp[x]){
            bzx=x;
            bzy=father;
            while (stk[top]!=x){
                hu[++cnt]=stk[top];
                ls[cnt]=ls[cnt-1]+1;
                bzf[stk[top]]=1;
                top--;
            }
            hu[++cnt]=stk[top];
            ls[cnt]=ls[cnt-1]+1;
            bzf[stk[top]]=1;
            top--;
            return;
        }
        bzp[x]=1;
        stk[++top]=x;
        for (i=q[x];i;i=e[i].next){
            y=e[i].to;
            if (y!=father)
                dfsp(y,x);
            if (bzx)
                return;
        }
        top--;
    }
    void change(ll x,ll l,ll r,ll k){
        if (l==r){
            f[x].sum++;
            return;
        }
        ll mid=(l+r)/2;
        if (k<=mid)
            change(x*2,l,mid,k);
        else
            change(x*2+1,mid+1,r,k);
        f[x].sum=f[x*2].sum+f[x*2+1].sum;
    }
    ll find(ll x,ll l,ll r,ll l1,ll r1){
        if (l1<=l&&r1>=r)
            return f[x].sum;
        ll sum=0,mid=(l+r)/2;
        if (l1<=mid)
            sum+=find(x*2,l,mid,l1,r1);
        if (r1>mid)
            sum+=find(x*2+1,mid+1,r,l1,r1);
        return sum;
    }
    int main(){
        scanf("%lld%lld%lld",&n,&m,&len);
        len--;
        for (i=1;i<=m;i++){
            scanf("%lld%lld",&x,&y);
            insert(x,y);
            insert(y,x);
        }
        dfsp(1,0);
        mxs[0]=1e9;
        root=0;
        sizen=n;
        getroot(1,0);
        dfs(root);
        if (m==n-1){
            printf("%lld
    ",ans);
            return 0;
        }
        num=0;
        dfs1(bzx,0,0,0);
        for (i=1;i<=num;i++)
            change(1,0,n,a[i]);
        for (i=cnt-1;i>=1;i--){
            num=0;
            dfs1(hu[i],0,0,0);
            for (j=1;j<=num;j++)
                ans+=find(1,0,n,len-ls[i]-a[j],n);
            for (j=1;j<=num;j++)
                change(1,0,n,a[j]+ls[cnt]-ls[i]);
        }
        printf("%lld
    ",ans);
        return 0;
    }
  • 相关阅读:
    ibatis命名空间namespace的使用
    MyEclipse 下新建Flex与JAVA交互项目
    第2章 TCP/IP 和Internet
    第一部分:TCP/IP 基础 第一章 开放式通信模型简介
    01-布局扩展-利用盒模型完成圣杯布局(双飞翼布局)
    01-布局扩展-用calc来计算实现双飞翼布局
    01-布局扩展-BFC完成圣杯布局
    Nginx
    uni-app mpvue wepy websocket的介绍
    taro 使用taro中的vue来完成小程序的开发
  • 原文地址:https://www.cnblogs.com/Mohogany/p/13735423.html
Copyright © 2011-2022 走看看