zoukankan      html  css  js  c++  java
  • 2.27模拟赛

    pdf版题面

    水题赛无题解

    sol:可以用权值并查集搞,但感觉还是建图跑bfs比较容易

    定义S[i]表示前缀和

    读入a,b,c;就是S[a-1] + c=S[b],那就从a-1向b连一条c,b向a-1连一条-c

    但这样有可能这张图并不联通,于是每次bfs时给节点染色,颜色不同显然to hard

    询问随便处理下就可以了

    /*
        S[3]-S[0]=10
        S[3]-S[2]=5
    */
    #include <bits/stdc++.h>
    using namespace std;
    #define int long long
    typedef int ll;
    inline ll read()
    {
        ll S=0;
        bool f=0;
        char ch=' ';
        while(!isdigit(ch))
        {
            f|=(ch=='-'); ch=getchar();
        }
        while(isdigit(ch))
        {
            S=(S<<3)+(S<<1)+(ch-'0'); ch=getchar();
        }
        return (f)?(-S):(S);
    }
    #define R(x) x=read()
    inline void write(ll x)
    {
        if(x<0)
        {
            putchar('-'); x=-x;
        }
        if(x<10)
        {
            putchar(x+'0'); return;
        }
        write(x/10);
        putchar((x%10)+'0');
        return;
    }
    #define W(x) write(x),putchar(' ')
    #define Wl(x) write(x),putchar('
    ')
    const int N=100005,M=200005;
    int n,m,Q,Cnt=0;
    namespace Dijkstra
    {
        int tot=0,Next[M],to[M],val[M],head[N];
        int Cor[N];
        inline void add(int x,int y,int z)
        {
            Next[++tot]=head[x];
            to[tot]=y;
            val[tot]=z;
            head[x]=tot;
            return;
        }
        struct Record
        {
            int Weiz,Val;
        };
        inline bool operator<(Record p,Record q)
        {
            return p.Val>q.Val;
        }
        priority_queue<Record>Queue;
        bool Arr[N];
        int Dis[N];
        inline void Run(int S,int Co)
        {
            Cor[S]=Co;
            Queue.push((Record){S,Dis[S]=0});
            int i;
            while(!Queue.empty())
            {
                Record tmp=Queue.top();
                Cor[tmp.Weiz]=Co;
                Queue.pop();
                if(Arr[tmp.Weiz]) continue;
                Arr[tmp.Weiz]=1;
                for(i=head[tmp.Weiz];i;i=Next[i])
                {
                    if(Dis[to[i]]>tmp.Val+val[i])
                    {
                        Dis[to[i]]=tmp.Val+val[i];
                        if(!Arr[to[i]]) Queue.push((Record){to[i],Dis[to[i]]});
                    }
                }
            }
        }
        inline void Solve(int x,int y)
        {
            y++;
            if(Cor[x]!=Cor[y])
            {
                puts("Too Hard");
            }
            else
            {
                Wl(Dis[y]-Dis[x]);    
            }
        }
        inline void Init()
        {
            memset(head,0,sizeof head);
            memset(Arr,0,sizeof Arr);
            memset(Dis,63,sizeof Dis);
            memset(Cor,0,sizeof Cor);
            return;
        }
    }
    signed main()
    {
        freopen("sing.in","r",stdin);
        freopen("sing.out","w",stdout);
        R(n); R(m);
        int i;
        Dijkstra::Init();
        for(i=1;i<=m;i++)
        {
            int x=read(),y=read()+1,z=read();
            Dijkstra::add(x,y,z);
            Dijkstra::add(y,x,-z);
        }
        for(i=1;i<=n;i++) if(!Dijkstra::Arr[i])
        {
            Dijkstra::Run(i,++Cnt);
        }
        R(Q);
        for(i=1;i<=Q;i++)
        {
            int x=read(),y=read();
            Dijkstra::Solve(x,y);
        }
        return 0;
    }
    /*
    input
    4 2
    1 3 10
    3 3 5
    2
    1 2
    1 4
    output
    5
    Too Hard
    */
    View Code

    sol:容易发现这个n非常大,肯定不能直接上最短路

    于是发现跑最短路时,真正有用的是那些中间有墙倒掉的点,对于这2*m个点

    首先在有墙倒的地方建一条权值1的双向边

    在对2*m个点排序,p[i]向p[i+1]连一条权值为(p[i+1]-p[i])的边

    要离散。。。

    #include <bits/stdc++.h>
    using namespace std;
    #define int long long
    typedef int ll;
    inline ll read()
    {
        ll S=0;
        bool f=0;
        char ch=' ';
        while(!isdigit(ch))
        {
            f|=(ch=='-'); ch=getchar();
        }
        while(isdigit(ch))
        {
            S=(S<<3)+(S<<1)+(ch-'0'); ch=getchar();
        }
        return (f)?(-S):(S);
    }
    #define R(x) x=read()
    inline void write(ll x)
    {
        if(x<0)
        {
            putchar('-'); x=-x;
        }
        if(x<10)
        {
            putchar(x+'0'); return;
        }
        write(x/10);
        putchar((x%10)+'0');
        return;
    }
    #define W(x) write(x),putchar(' ')
    #define Wl(x) write(x),putchar('
    ')
    const int N=500005,M=1000005;
    int n,m;
    int X[N],Y[N];
    int P[N<<1];
    int Pos[N<<1];
    map<int,int>Map;
    namespace Dijkstra
    {
        int tot=0,Next[M],to[M],val[M],head[N];
        inline void add(int x,int y,int z)
        {
            Next[++tot]=head[x];
            to[tot]=y;
            val[tot]=z;
            head[x]=tot;
            return;
        }
        struct Record
        {
            int Weiz,Val;
        };
        inline bool operator<(Record p,Record q)
        {
            return p.Val>q.Val;
        }
        priority_queue<Record>Queue;
        bool Arr[N];
        int Dis[N];
        inline void Run(int S)
        {
            Queue.push((Record){S,Dis[S]=0});
            int i;
            while(!Queue.empty())
            {
                Record tmp=Queue.top();
                Queue.pop();
                if(Arr[tmp.Weiz]) continue;
                Arr[tmp.Weiz]=1;
                for(i=head[tmp.Weiz];i;i=Next[i])
                {
                    if(Dis[to[i]]>tmp.Val+val[i])
                    {
                        Dis[to[i]]=tmp.Val+val[i];
                        if(!Arr[to[i]]) Queue.push((Record){to[i],Dis[to[i]]});
                    }
                }
            }
        }
        inline void Init()
        {
            memset(head,0,sizeof head);
            memset(Arr,0,sizeof Arr);
            memset(Dis,63,sizeof Dis);
            return;
        }
    }
    #define Dj Dijkstra
    signed main()
    {
        freopen("lh.in","r",stdin);
        freopen("lh.out","w",stdout);
        R(n); R(m);
        int i;
        Dj::Init();
        for(i=1;i<=m;i++)
        {
            X[i]=read();
            Y[i]=read();
            if(!Map[X[i]])
            {
                P[Map[X[i]]=++*P]=X[i];
            }
            if(!Map[Y[i]])
            {
                P[Map[Y[i]]=++*P]=Y[i];
            }
            Dj::add(Map[X[i]],Map[Y[i]],1);
            Dj::add(Map[Y[i]],Map[X[i]],1);
        }
        if(!Map[1])
        {
            P[Map[1]=++*P]=1;
        }
        if(!Map[n])
        {
            P[Map[n]=++*P]=n;
        }
        sort(P+1,P+*P+1);
        for(i=1;i<*P;i++)
        {
            Dj::add(Map[P[i]],Map[P[i+1]],P[i+1]-P[i]);
            Dj::add(Map[P[i+1]],Map[P[i]],P[i+1]-P[i]);
        }
        Dj::Run(Map[1]);
        Wl(Dj::Dis[Map[n]]);
        return 0;
    }
    /*
    input
    31
    9
    4 15
    10 25
    13 30
    1 6
    2 9
    6 19
    9 24
    10 27
    1 4
    output
    6
    Too Hard
    */
    View Code

    sol:看上去很厉害其实只是MST的板子罢了,一堆描述只是在故弄玄虚,就是说没有环。

    Prim随便水

    #include <bits/stdc++.h>
    using namespace std;
    typedef int ll;
    inline ll read()
    {
        ll S=0;
        bool f=0;
        char ch=' ';
        while(!isdigit(ch))
        {
            f|=(ch=='-'); ch=getchar();
        }
        while(isdigit(ch))
        {
            S=(S<<3)+(S<<1)+(ch-'0'); ch=getchar();
        }
        return (f)?(-S):(S);
    }
    #define R(x) x=read()
    inline void write(ll x)
    {
        if(x<0)
        {
            putchar('-'); x=-x;
        }
        if(x<10)
        {
            putchar(x+'0'); return;
        }
        write(x/10);
        putchar((x%10)+'0');
        return;
    }
    #define W(x) write(x),putchar(' ')
    #define Wl(x) write(x),putchar('
    ')
    const int N=5005;
    int n;
    struct Point
    {
        int x,y;
    }P[N];
    double DD[N];
    int Father[N];
    bool Vis[N];
    inline double Calc(int i,int j)
    {
        double ix=P[i].x,iy=P[i].y,jx=P[j].x,jy=P[j].y;
        return sqrt((ix-jx)*(ix-jx)+(iy-jy)*(iy-jy));
    }
    int main()
    {
        freopen("torture.in","r",stdin);
        freopen("torture.out","w",stdout);
        int i,j;
        R(n);
        for(i=1;i<=n;i++)
        {
            Father[i]=i;
            R(P[i].x);
            R(P[i].y);
        }
        int step;
        double ans=0;
        for(i=2;i<=n;i++) DD[i]=1e15;
        DD[1]=0;
        for(step=1;step<n;step++)
        {
            int u=-1;
            for(i=1;i<=n;i++) if((!Vis[i])&&(u==-1||DD[i]<DD[u])) u=i;
            Vis[u]=1;
            for(i=1;i<=n;i++) if((!Vis[i])&&(DD[i]>Calc(u,i)))
            {
                DD[i]=Calc(u,i);
            }
        }
        for(i=1;i<=n;i++) ans+=DD[i];
        printf("%.2lf
    ",ans);
        return 0;
    }
    /*
    input
    4
    0 0
    1 2
    -1 2
    0 4
    output
    6.47
    */
    View Code

    updata:首先对于题面有一处修正,两个点之间的距离是min(|Xa-Xb|,|Ya-Yb|,|Za-Zb|),题面中少了个min,而且也不是曼哈顿距离

    sol:对三维分别排序,得到3*(n-1)条边,Kruskal直接上

    Xjb证明:只有一维时,显然排好序后第i个向i+1连边最优,

    当有三维时,Kruskal保证当前边权是没选过的中最小的,相当于已经在3维中去过min了,于是可以直接做了

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    inline ll read()
    {
        ll S=0;
        bool f=0;
        char ch=' ';
        while(!isdigit(ch))
        {
            f|=(ch=='-'); ch=getchar();
        }
        while(isdigit(ch))
        {
            S=(S<<3)+(S<<1)+(ch-'0'); ch=getchar();
        }
        return (f)?(-S):(S);
    }
    #define R(x) x=read()
    inline void write(ll x)
    {
        if(x<0)
        {
            putchar('-'); x=-x;
        }
        if(x<10)
        {
            putchar(x+'0'); return;
        }
        write(x/10);
        putchar((x%10)+'0');
        return;
    }
    #define W(x) write(x),putchar(' ')
    #define Wl(x) write(x),putchar('
    ')
    const int N=100005;
    int n;
    int Father[N];
    struct Point
    {
        int Weiz,Id;
    }X[N],Y[N],Z[N];
    inline bool Point_cmp(Point a,Point b)
    {
        return a.Weiz<b.Weiz;
    }
    int cnt=0;
    struct Edge
    {
        int U,V,Bianquan;
    }E[N*3];
    inline bool Edge_cmp(Edge a,Edge b)
    {
        return a.Bianquan<b.Bianquan;
    }
    inline int Get_Father(int x)
    {
        return (Father[x]==x)?(x):(Father[x]=Get_Father(Father[x]));
    }
    int main()
    {
        freopen("time.in","r",stdin);
        freopen("time.out","w",stdout);
        int i;
        R(n);
        for(i=1;i<=n;i++)
        {
            X[i]=(Point){read(),i};
            Y[i]=(Point){read(),i};
            Z[i]=(Point){read(),i};
        }
        sort(X+1,X+n+1,Point_cmp);
        for(i=1;i<n;i++)
        {
            E[++cnt]=(Edge){X[i].Id,X[i+1].Id,X[i+1].Weiz-X[i].Weiz};
        }
        sort(Y+1,Y+n+1,Point_cmp);
        for(i=1;i<n;i++)
        {
            E[++cnt]=(Edge){Y[i].Id,Y[i+1].Id,Y[i+1].Weiz-Y[i].Weiz};
        }
        sort(Z+1,Z+n+1,Point_cmp);
        for(i=1;i<n;i++)
        {
            E[++cnt]=(Edge){Z[i].Id,Z[i+1].Id,Z[i+1].Weiz-Z[i].Weiz};
        }
        sort(E+1,E+cnt+1,Edge_cmp);
        for(i=1;i<=n;i++)
        {
            Father[i]=i;
        }
        ll ans=0;
        int Bians=0;
        for(i=1;i<=cnt;i++)
        {
            int u=E[i].U,v=E[i].V;
            int uu=Get_Father(u),vv=Get_Father(v);
            if(uu==vv) continue;
            ans+=1ll*E[i].Bianquan;
            Father[uu]=vv;
            if(++Bians==n-1) break;
        }
        Wl(ans);
        return 0;
    }
    /*
    input
    5
    11 -15 -15
    14 -5 -15
    -1 -1 -5
    10 -4 -1
    19 -4 19
    output
    4
    */
    View Code
  • 相关阅读:
    【2019.7.10】树上差分 杂[LCA 倍增][树上差分 点差分 边差分]
    【luogu4145】 上帝造题的七分钟2 / 花神游历各国 [线段树]
    【luogu1198】 [JSOI2008]最大数 [线段树]
    【luogu2783】 有机化学之神偶尔会做作弊 [tarjan 缩点][LCA]
    【luogu3388】 【模板】割点(割顶)[tarjan 割点]
    【luogu2272】 [ZJOI2007]最大半连通子图 [tarjan 缩点][拓扑排序]
    【luogu2194】HXY烧情侣 [tarjan 缩点]
    【luogu3627】 [APIO2009]抢掠计划 [tarjan 缩点][最短路]
    【luogu3398】 仓鼠找sugar [LCA 倍增]
    【luogu2746】 [USACO5.3]校园网Network of Schools [tarjan 缩点]
  • 原文地址:https://www.cnblogs.com/gaojunonly1/p/10453070.html
Copyright © 2011-2022 走看看