zoukankan      html  css  js  c++  java
  • [jzoj 5926] [NOIP2018模拟10.25] naive 的图 解题报告(kruskal重构树+二维数点)

    题目链接:

    https://jzoj.net/senior/#main/show/5926

    题目:

    题解:

    显然最小的最大路径在最小生成树上(最小生成树=最小瓶颈生成树)

    于是我们建出kruskal重构树,两个节点的d值就是lca代表的边的边权,问题转化为对于每个lca计算以它为lca的且满足$|c_u-c_v|$的点对的个数

    对于每个lca我们枚举 size 较小的那棵子树内的点(每次选择size较小的暴力计算就是启发式合并),算出在另一棵子树中能与它组成点对的点的个数。这个问题实际上就是询问在 dfs 序的一段区间上并且颜色不在一段区间内的点 数,二维数点问题可以离线树状数组完成。

    #include<algorithm>
    #include<cstring>
    #include<cstdio>
    #include<iostream>
    using namespace std;
    typedef long long ll;
    
    const int N=2e5+15;
    const int M=5e5+15;
    int n,m,xys,tot,tim,ask;
    ll L,mx;
    int fa[N<<1],in[N<<1],dfn[N<<1],siz[N<<1],lf[N<<1],rf[N<<1],ED[N<<1],t[N<<1];
    ll c[N],ANS[N<<1],val[N<<1];
    struct EDGE{
        int u,v;
        ll w;
    }e[M];
    bool operator <(EDGE a,EDGE b) {return a.w<b.w;}
    struct QUE{
        ll x,y;
        int k,id;
    }q[N<<6];
    bool operator <(QUE a,QUE b){return (a.x<b.x)||(a.x==b.x&&a.k>b.k);}
    inline char nc(){
        static char buf[10000000],*p1=buf,*p2=buf;
        return p1==p2&&(p2=(p1=buf)+fread(buf,1,10000000,stdin),p1==p2)?EOF:*p1++;
    }
    inline int read(){
        char ch=nc();int s=0,f=1;
        while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=nc();}
        while (ch>='0'&&ch<='9') {s=(s<<3)+(s<<1)+ch-'0';ch=nc();}
        return s*f;
    }
    int find(int x)
    {
        if (fa[x]!=x) fa[x]=find(fa[x]);
        return fa[x];
    }
    void dfs(int x)
    {
        dfn[x]=++tim;siz[x]=1;
        if (x<=n) {ED[x]=dfn[x];return;}
        if (lf[x]) dfs(lf[x]);
        if (rf[x]) dfs(rf[x]);
        ED[x]=tim;
        if (siz[lf[x]]>siz[rf[x]]) swap(lf[x],rf[x]);
        siz[x]+=siz[lf[x]]+siz[rf[x]];
    }
    void ASK(int x,int st,int ed,int id)
    {
        if (x<=n)
        {
            ll p1,p2;
            p1=0;p2=c[x]-L;
            if (p2>=p1)
            {
                q[++ask]=(QUE){p2,ed,1,id};
                q[++ask]=(QUE){p1-1,ed,-1,id};
                q[++ask]=(QUE){p2,st-1,-1,id};
                q[++ask]=(QUE){p1-1,st-1,1,id};
            }
            p1=c[x]+L;p2=mx;
            if (L==0) ++p1;
            if (p1<=p2)
            {
                q[++ask]=(QUE){p2,ed,1,id};
                q[++ask]=(QUE){p1-1,ed,-1,id};
                q[++ask]=(QUE){p2,st-1,-1,id};
                q[++ask]=(QUE){p1-1,st-1,1,id};
            }
            return;
        }
        if (lf[x]) ASK(lf[x],st,ed,id);if (rf[x]) ASK(rf[x],st,ed,id);
    }
    void modify(int x,int y)
    {
        while (x<=tim) 
        {
            t[x]+=y;
            x+=x&-x;
        }
    }
    int query(int x)
    {
        int re=0;
        while (x)
        {
            re+=t[x];
            x-=x&-x;
        }
        return re;
    }
    int main()
    {
        freopen("graph.in","r",stdin);
        freopen("graph.out","w",stdout);
        n=read();m=read();L=read();
        for (int i=1;i<=n;i++) c[i]=read(),mx=max(mx,c[i]),fa[i]=i;
        for (int i=1;i<=m;i++)
        {
            e[i].u=read();e[i].v=read();e[i].w=read();
        }
        sort(e+1,e+1+m);
        for (int i=n+1;i<=n<<1;i++) fa[i]=i;
        int cnt=0;xys=n;
        for (int i=1;i<=m;i++)
        {
            int u=e[i].u,v=e[i].v;
            int fu=find(u),fv=find(v);
            if (fu!=fv)
            {
                val[++xys]=e[i].w;    
                fa[fu]=xys;fa[fv]=xys;
                lf[xys]=fu;rf[xys]=fv;
                in[fu]++;in[fv]++;
                ++cnt;
                if (cnt==n-1) break;
            }
        }
        for (int i=1;i<=xys;i++) if (!in[i]) dfs(i);
        for (int i=1;i<=n;i++) 
        {
            q[++ask]=(QUE){c[i],dfn[i],2,0};
        }
        for (int i=n+1;i<=xys;i++)
        {
            ASK(lf[i],dfn[rf[i]],ED[rf[i]],i);
        }
        sort(q+1,q+1+ask);
        for (int i=1;i<=ask;i++)
        {
            if (!q[i].id) modify(q[i].y,1);
            else ANS[q[i].id]+=q[i].k*query(q[i].y);
        }
        ll ans=0;
        for (int i=n+1;i<=xys;i++) ans+=ANS[i]*1ll*val[i];
        printf("%lld
    ",ans);
        return 0;
    }
  • 相关阅读:
    复杂声明的正确解读(*、()、[])
    (多张图片打包为Zip返回前端下载) 记NetCore HttpClient.GetStreamAsync()返回只读流,Stream的Length属性不可用,报错的问题。
    ### Vue开发环境搭建
    计算机网络原理----CRC编码相关问题及解题思路
    CentOS7安装MongoDB4.4.4
    树莓派4B安装.NET Core 3.1 SDK
    基于数据库的代码自动生成工具,生成JavaBean、生成数据库文档、生成前后端代码等(TableGo v7.0.0版)
    解决Unity启动报错 Assertion failed on expression: 'SUCCEEDED(hr)'
    @RabbitListener注解导致spring bean注入属性为空 解决方案
    一文彻底讲透@Async注解的原理和使用方法
  • 原文地址:https://www.cnblogs.com/xxzh/p/9853184.html
Copyright © 2011-2022 走看看