码迷,mamicode.com
首页 > 其他好文 > 详细

模拟赛T2 中继系统

时间:2020-02-16 13:25:09      阅读:61      评论:0      收藏:0      [点我收藏+]

标签:getc   clu   main   变化   关系   左右   check   return   def   

技术图片
技术图片

分析:
实际上就分析一发最小生成树的变化
但是时间是到正无穷,如果对于每个时刻都维护一下,显然是不可做的
我们尝试分析一下最小生成树在什么时候改变
当非最小生成树的边比最小生成树的边小的时候,最小生成树就会改变
尝试枚举一对边复杂度为\(O(n^4)\)
这对边在什么时候大小关系产生改变,实际上是一个一元二次方程
直接暴力解就好了
然后对于每一个时间点,如果维护的生成树中,一对边一个在树内,一个在树外,就要对生成树进行改变
但是不能全部维护复杂度为\(O(n^6)\),我们只需要把相关的链上的边单独维护,这样复杂度就变成了\(O(n^5)\)
常数上为除以10左右,写得漂亮一点就过了2333

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<vector>
#include<set>
#include<queue>

#define maxn 55
#define INF 0x3f3f3f3f
#define MOD 998244353
#define eps 1e-7

using namespace std;

inline long long getint()
{
    long long num=0,flag=1;char c;
    while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
    while(c>='0'&&c<='9')num=num*10+c-48,c=getchar();
    return num*flag;
}

struct edge{
    int u,v;
    double w;
}L[maxn*maxn],stk[2][maxn],now[maxn*maxn];
struct node{
    int u,v;
    double t;
}T[maxn*maxn*maxn*maxn];
int n,ans;
double p[maxn][20];
int cnte,cntl,cntnow,tp[2];
int fa[maxn];
bool vis[maxn][maxn];

inline double geta(int i,int j)
{double num=0;for(int k=1;k<=3;k++)num+=(p[i][k+3]-p[j][k+3])*(p[i][k+3]-p[j][k+3]);return num;}
inline double getb(int i,int j)
{double num=0;for(int k=1;k<=3;k++)num+=2*(p[i][k]-p[j][k])*(p[i][k+3]-p[j][k+3]);return num;}
inline double getc(int i,int j)
{double num=0;for(int k=1;k<=3;k++)num+=(p[i][k]-p[j][k])*(p[i][k]-p[j][k]);return num;}

inline void insert(int i,int j,double t)
{if(t<=0)return;T[++cnte].u=i,T[cnte].v=j,T[cnte].t=t;}
bool cmp1(node a,node b){return a.t<b.t;}
bool cmp2(edge a,edge b){return a.w<b.w;}
bool cmp3(edge a,edge b){return a.u==b.u?a.v<b.v:a.u<b.u;}

inline int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
inline void Krus()
{
    memset(vis,0,sizeof vis);
    sort(L+1,L+cntl+1,cmp2);
    for(int i=1;i<=n;i++)fa[i]=i;
    for(int i=1;i<=cntl;i++)
    {
        int r1=find(L[i].u),r2=find(L[i].v);
        if(r1!=r2)
        {
            fa[r2]=r1;
            now[++cntnow]=L[i];
            vis[L[i].u][L[i].v]=vis[L[i].v][L[i].u]=true;
        }
    }
}

inline bool check(edge x){return vis[x.u][x.v]?1:0;}
inline void solve(int id,double t)
{
    for(int i=1,u,v;i<=cntnow;i++)
    {
        u=now[i].u,v=now[i].v;now[i].w=0;
        for(int k=1;k<=3;k++)now[i].w+=(p[u][k]+t*p[u][k+3]-p[v][k]-t*p[v][k+3])*(p[u][k]+t*p[u][k+3]-p[v][k]-t*p[v][k+3]);
    }
    for(int i=1;i<=n;i++)fa[i]=i;
    sort(now+1,now+cntnow+1,cmp2);
    tp[id]=0;
    for(int i=1;i<=cntnow;i++)
    {
        int r1=find(now[i].u),r2=find(now[i].v);
        if(r1!=r2)
        {
            fa[r2]=r1;++tp[id];
            stk[id][tp[id]].u=now[i].u,stk[id][tp[id]].v=now[i].v;
        }
    }
}

int main()
{
    n=getint();
    for(int i=1;i<=n;i++)for(int k=1;k<=6;k++)p[i][k]=getint();
    for(int i=1;i<=n;i++)
        for(int j=i+1;j<=n;j++)
        {
            L[++cntl].u=i,L[cntl].v=j;
            for(int k=1;k<=3;k++)L[cntl].w+=(p[i][k]-p[j][k])*(p[i][k]-p[j][k]);
        }
    for(int i=1;i<=cntl;i++)
        for(int j=i+1;j<=cntl;j++)
        {
            double a=geta(L[i].u,L[i].v)-geta(L[j].u,L[j].v),b=getb(L[i].u,L[i].v)-getb(L[j].u,L[j].v),c=getc(L[i].u,L[i].v)-getc(L[j].u,L[j].v);
            if(fabs(a)<eps)
            {
                if(fabs(b)<eps)continue;
                insert(i,j,-c/b);
            }
            else
            {
                double delta=b*b-4*a*c;if(delta<0)continue;
                insert(i,j,(-b+sqrt(delta))/(2*a)),insert(i,j,(-b-sqrt(delta))/(2*a));
            }
        }
    sort(T+1,T+cnte+1,cmp1);
    ans=1;Krus();
    sort(L+1,L+cntl+1,cmp3);
    for(int i=1,flag=0,p1,p2;i<=cnte;i++)
    {
        p1=check(L[T[i].u]),p2=check(L[T[i].v]);
        if(p1^p2)
        {
            if(!p1)now[++cntnow]=L[T[i].u];
            else now[++cntnow]=L[T[i].v];
            flag=1;
        }
        if(fabs(T[i].t-T[i+1].t)>eps&&flag)
        {
            solve(0,T[i].t-eps);
            solve(1,T[i].t+eps);
            sort(stk[0]+1,stk[0]+tp[0]+1,cmp3);
            sort(stk[1]+1,stk[1]+tp[1]+1,cmp3);
            int g=0;
            cntnow=0;
            memset(vis,0,sizeof vis);
            for(int i=1;i<n;i++)
            {
                if(!(stk[0][i].u==stk[1][i].u&&stk[0][i].v==stk[1][i].v))g=1;
                now[++cntnow]=stk[1][i];
                vis[stk[1][i].u][stk[1][i].v]=vis[stk[1][i].v][stk[1][i].u]=true;
            }
            ans+=g;
        }
        if(fabs(T[i].t-T[i+1].t)>eps)flag=0;
    }
    printf("%d\n",ans);
}

技术图片

模拟赛T2 中继系统

标签:getc   clu   main   变化   关系   左右   check   return   def   

原文地址:https://www.cnblogs.com/Darknesses/p/12316202.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!