[通信题] JOI Open Contest 2017 Amusement Park

题目大意:
这是一道通信题
第一个程序 输入一张无向图的点和边 再给一个2^60以内的数 第一个程序要给每个点赋值0/1
第二个程序也会读入这张图 然后读入当前点编号以及当前点的值,其他点的值一律不知,每次可以调用一个函数走向一个相邻的点,并得知这个点的值,120步以内得出只有第一个程序知道的那个数

VIEW PROBLEM - AMUSEMENT PARK (JOI17_AMUSEMENT_PARK)

做的第一道通信题,感觉这题蛮简单,可能不习惯,搞了好久

对于一个n连通块 可以按欧拉序走 2(n-1) 步走过所有点
随便拎出来一个包含根的size60连通块,要是起点在这个连通块就直接dfs这个连通块,不然对于其他点,必然可以搞出一个连通块,跟他父亲所在的连通块只差一个点
每个连通块存下六十个二进制位
每次只要走过所在连通块就行了

代码略丑

#include "Joi.h"
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cassert>
using namespace std;


#define V G[p].v

namespace JOI{

  const int N=10005;
  const int M=20005;

  struct edge{
    int u,v,next;  
  }G[M<<1];
  int head[N],inum=1;
  inline void add(int u,int v,int p){
    G[p].u=u; G[p].v=v; G[p].next=head[u]; head[u]=p;
  }

  const int B=60;

  int tag[M<<1];
  int fat[N],vst[N];

  inline void dfs(int u){
    vst[u]=1;
    for (int p=head[u];p;p=G[p].next)
      if (!vst[V])
    tag[p]=tag[p^1]=1,fat[V]=u,dfs(V);
  }

  struct CC{
    int idx[B+5],deg[B+5];
    bool a[B+5][B+5];
    int find(int u){ for (int i=1;i<=B;i++) if (idx[i]==u) return i; return 0;}
    void addd(int u,int v){
      u=find(u); v=find(v);
      deg[u]++; deg[v]++; a[u][v]=a[v][u]=1;
    }
  }C[N];
  int ncnt=1;

  int tot=0;
  int rt[N],ins[N];

  inline void pre(int u,int fa){
    if (tot>=B) return;
    rt[u]=1; ins[u]=1; C[1].idx[++tot]=u;
    for (int p=head[u];p;p=G[p].next)
      if (tag[p] && V!=fa)
    pre(V,u);
  }

  int clk;

  inline void build(int u,int fa){
    if (!rt[u]){
      rt[u]=++ncnt;
      C[rt[u]]=C[rt[fa]]; CC &F=C[rt[u]];
      int x;
      for (int i=1;i<=B;i++)
    if (F.deg[i]==1 && F.idx[i]!=fa){
      for (int j=1;j<=B;j++)
        if (F.a[i][j]==1)
          F.a[i][j]=0,F.a[j][i]=0,F.deg[j]--,F.deg[i]--;
      x=i; break;
    }
      F.idx[x]=u; F.addd(u,fa); 
    }
    for (int p=head[u];p;p=G[p].next)
      if (tag[p] && V!=fa)
    build(V,u);
  }

  int Idx[N];
  int w[N];
}

void Joi(int n, int m, int A[], int B[], long long X, int T) {
  using namespace JOI;
  for (int i=0;i<60;i++) w[i]=X&1,X>>=1;
  for (int i=0;i<m;i++)
    add(A[i]+1,B[i]+1,++inum),add(B[i]+1,A[i]+1,++inum);
  dfs(1);
  pre(1,0);
  for (int p=2;p<=inum;p+=2)
    if (tag[p] && ins[G[p].u] && ins[G[p].v])
      C[1].addd(G[p].u,G[p].v);
  build(1,0);
  for (int i=1;i<=n;i++){
    int tmp=Idx[i];
    Idx[i]=C[rt[i]].find(i);
    assert(tmp==0 || tmp==Idx[i]);
    MessageBoard(i-1,w[Idx[i]-1]);
  }
}

#undef V
#include "Ioi.h"
#include<cstdio>
#include<cstdlib>
using namespace std;
typedef long long ll;

#define V G[p].v

namespace IOI{
  const int N=10005;
  const int M=20005;

  struct edge{
    int u,v,next;  
  }G[M<<1];
  int head[N],inum=1;
  inline void add(int u,int v,int p){
    G[p].u=u; G[p].v=v; G[p].next=head[u]; head[u]=p;
  }

  const int B=60;

  int tag[M<<1];
  int fat[N],vst[N];

  inline void dfs(int u){
    vst[u]=1;
    for (int p=head[u];p;p=G[p].next)
      if (!vst[V])
    tag[p]=tag[p^1]=1,fat[V]=u,dfs(V);
  }

  struct CC{
    int idx[B+5],deg[B+5];
    bool a[B+5][B+5];
    int find(int u){ for (int i=1;i<=B;i++) if (idx[i]==u) return i; return 0;}
    void addd(int u,int v){
      u=find(u); v=find(v);
      deg[u]++; deg[v]++; a[u][v]=a[v][u]=1;
    }
  }C[N];
  int ncnt=1;

  int tot=0;
  int rt[N],ins[N];

  inline void pre(int u,int fa){
    if (tot>=B) return;
    rt[u]=1; ins[u]=1; C[1].idx[++tot]=u;
    for (int p=head[u];p;p=G[p].next)
      if (tag[p] && V!=fa)
    pre(V,u);
  }

  int clk;

  inline void build(int u,int fa){
    if (!rt[u]){
      rt[u]=++ncnt;
      if (u==192)
    rt[u]=ncnt;
      C[rt[u]]=C[rt[fa]]; CC &F=C[rt[u]];
      int x;
      for (int i=1;i<=B;i++)
    if (F.deg[i]==1 && F.idx[i]!=fa){
      for (int j=1;j<=B;j++)
        if (F.a[i][j]==1)
          F.a[i][j]=0,F.a[j][i]=0,F.deg[j]--,F.deg[i]--;
      x=i; break;
    }
      F.idx[x]=u; F.addd(u,fa); 
    }
    for (int p=head[u];p;p=G[p].next)
      if (tag[p] && V!=fa)
    build(V,u);
  }

  int Idx[N],Ins[N];
  int Vst[N];
  ll Ans=0;
  int w[N];

  inline void decode(int u){
    Vst[u]=1;
    for (int p=head[u];p;p=G[p].next)
      if (tag[p] && !Vst[V] && Ins[V]){
    int d=Move(V-1); w[Idx[V]-1]=d;
    Ans+=((ll)d<<(Idx[V]-1));
    decode(V);
    Move(u-1);
      }
  }
}

long long Ioi(int n, int m, int A[], int B[], int P, int _V, int T) {
  using namespace IOI;
  for (int i=0;i<m;i++)
    add(A[i]+1,B[i]+1,++inum),add(B[i]+1,A[i]+1,++inum);
  dfs(1);
  pre(1,0);
  for (int p=2;p<=inum;p+=2)
    if (tag[p] && ins[G[p].u] && ins[G[p].v])
      C[1].addd(G[p].u,G[p].v);
  build(1,0);
  for (int i=1;i<=n;i++)
    Idx[i]=C[rt[i]].find(i);
  for (int i=1;i<=IOI::B;i++) Ins[C[rt[P+1]].idx[i]]=1;
  Ans+=((ll)_V<<(Idx[P+1]-1)); w[Idx[P+1]-1]=_V; decode(P+1);
  return Ans;
}

#undef V
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值