• UOJ 347(洛谷4220) 【WC2018】通道——随机化


    题目:http://uoj.ac/problem/347

       https://www.luogu.org/problemnew/show/P4220

    先写了暴力分的44分。那个两棵树、其中一棵是编号连续的链、边权都是1的点好像可以线段树合并,但没写。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define ll long long
    using namespace std;
    ll rdn()
    {
      ll ret=0;bool fx=1;char ch=getchar();
      while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();}
      while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();
      return fx?ret:-ret;
    }
    ll Mx(ll a,ll b){return a>b?a:b;}
    const int N=1e5+5,M=3005,K=20;
    int n,hd[3][N],xnt,to[3][N<<1],nxt[3][N<<1];
    ll w[3][N<<1],dis[N],ans,ds2[M][M]; bool flag;
    void add(int t,int x,int y,ll z){to[t][++xnt]=y;nxt[t][xnt]=hd[t][x];hd[t][x]=xnt;w[t][xnt]=z;}
    void chk(int cr,int fa)
    {
      for(int i=hd[0][cr],v;i;i=nxt[0][i])
        if((v=to[0][i])!=fa)
          {
        bool fg=0;ll tw;
        for(int j=hd[1][cr];j;j=nxt[1][j])
          if(to[1][j]==v){fg=1;tw=w[1][j];break;}
        if(!fg||tw!=w[0][i]){flag=1;return;}
        for(int j=hd[2][cr];j;j=nxt[2][j])
          if(to[2][j]==v){fg=1;tw=w[2][j];break;}
        if(!fg||tw!=w[0][i]){flag=1;return;}
        chk(v,cr);if(flag)return;
          }
    }
    void dfs1(int cr,int fa)
    {
      ll mx=0,mx2=0;
      for(int i=hd[0][cr],v;i;i=nxt[0][i])
        if((v=to[0][i])!=fa)
          {
        dfs1(v,cr);ll tp=dis[v]+w[0][i];
        if(tp>mx)mx2=mx,mx=tp;
        else if(tp>mx2)mx2=tp;
          }
      ans=Mx(ans,mx+mx2);dis[cr]=mx;
    }
    void dfs2(int cr,int fa,ll lj,int t,int rt)
    {
      ds2[rt][cr]+=lj;
      for(int i=hd[t][cr],v;i;i=nxt[t][i])
        if((v=to[t][i])!=fa)dfs2(v,cr,lj+w[t][i],t,rt);
    }
    void solve2()
    {
      for(int t=0;t<3;t++)
        for(int i=1;i<=n;i++)dfs2(i,0,0,t,i);
      for(int i=1;i<=n;i++)
        for(int j=i+1;j<=n;j++)ans=Mx(ans,ds2[i][j]);
      printf("%lld
    ",ans);
    }
    int main()
    {
      n=rdn();
      for(int t=0;t<3;t++)
        {
          ll z;xnt=0;
          for(int i=1,u,v;i<n;i++)
        u=rdn(),v=rdn(),z=rdn(),add(t,u,v,z),add(t,v,u,z);
        }
      if(n<=3000){solve2();return 0;}
      chk(1,0);if(!flag){dfs1(1,0);printf("%lld
    ",ans*3);return 0;}
      return 0;
    }
    View Code

    正解要边分治和虚树,现在还不会。所以用了随机化。

    卡时间可以调用 clock() ,返回的是 CPU 周期,CLOCKS_PER_SEC 返回的是一秒运行了几个 CPU 周期,所以 clock() / CLOCKS_PER_SEC 可以算出运行了几秒。

    随机一个根,暴力算每个点到这个根的距离(3个距离求和),把距离当前根最远的那个点设为新的根,同时更新答案。做几次之后就再随机一个根。这个间隙可以小一些,10或者8之类的。

    可以打 vis[ ] 标记,作过根的点就不再作根了。

    还是通不过 UOJ 的 hack 数据。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<ctime>
    #define ll long long
    #define db double
    using namespace std;
    ll rdn()
    {
      ll ret=0;bool fx=1;char ch=getchar();
      while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();}
      while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();
      return fx?ret:-ret;
    }
    ll Mx(ll a,ll b){return a>b?a:b;}
    const int N=1e5+5,TL=3850;
    int n,hd[3][N],xnt,to[3][N<<1],nxt[3][N<<1];
    ll w[3][N<<1],dis[N],ds1[3005][3005],ans;
    bool vis[N];
    void add(int t,int x,int y,ll z){to[t][++xnt]=y;nxt[t][xnt]=hd[t][x];hd[t][x]=xnt;w[t][xnt]=z;}
    int clk(){return (db)clock()/CLOCKS_PER_SEC*1000;}//ms
    void dfs1(int cr,int fa,ll lj,int t,int rt)
    {
      ds1[rt][cr]+=lj;
      for(int i=hd[t][cr],v;i;i=nxt[t][i])
        if((v=to[t][i])!=fa)dfs1(v,cr,lj+w[t][i],t,rt);
    }
    void solve1()
    {
      for(int t=0;t<3;t++)
        for(int i=1;i<=n;i++)dfs1(i,0,0,t,i);
      for(int i=1;i<=n;i++)
        for(int j=i+1;j<=n;j++)ans=Mx(ans,ds1[i][j]);
      printf("%lld
    ",ans);
    }
    void dfs(int cr,int fa,ll lj,int t)
    {
      dis[cr]+=lj;
      for(int i=hd[t][cr],v;i;i=nxt[t][i])
        if((v=to[t][i])!=fa)dfs(v,cr,lj+w[t][i],t);
    }
    int cz(int rt)
    {
      for(int i=1;i<=n;i++)dis[i]=0;
      for(int t=0;t<3;t++)dfs(rt,0,0,t);
      int ret=0;
      for(int i=1;i<=n;i++)
        {
          if(dis[i]>ans)ans=dis[i];
          if(!vis[i]&&dis[i]>dis[ret])ret=i;
        }
      return ret;
    }
    int main()
    {
      n=rdn();ll z;
      for(int t=0;t<3;t++,xnt=0)
        for(int i=1,u,v;i<n;i++)
          u=rdn(),v=rdn(),z=rdn(),add(t,u,v,z),add(t,v,u,z);
      if(n<=5000){solve1();return 0;}
      int st=clk(); srand(time(0));srand(rand());
      int rt=rand()%n+1,T=0;
      while(clk()-st<TL)
        {
          T++; if(T==8)rt=rand()%n+1,T=0;
          if(vis[rt]){T=7;continue;}vis[rt]=1;
          rt=cz(rt);if(!rt)break;
        }
      printf("%lld
    ",ans);
      return 0;
    }
  • 相关阅读:
    实验 MPLS LDP配置
    IEEP-OSPF域内路由故障-现象与排障思路
    IEEP部署企业级网络工程-OSPF邻居关系故障排除
    IEEP部署企业级网络工程-网络故障-环路故障
    IEEP-网络实施-项目交付流程
    Python正则表达式
    如何解决TortoiseSVN不显示状态小图标问题
    如何在win下一键升级 python 所有包
    vmware workstation 与 device/credential guard 不兼容
    windows系统中在jupyter安装虚拟环境内核
  • 原文地址:https://www.cnblogs.com/Narh/p/10256881.html
Copyright © 2020-2023  润新知