BZOJ5100 : [POI2018]Plan metra

若$1$到$n$之间没有其它点,则$1$到$n$的距离为任意一点到它们距离的差值,按照距离关系判断每个点是挂在$1$上还是挂在$n$上即可。

否则$1$到$n$的距离只可能为任意一点到它们距离和的最小值,抽出$1$到$n$路径上所有点后,对于剩下的每个点判断它应该挂在那个点下面即可。

时间复杂度$O(n\log n)$。

 

#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;
const int N=500010;
int n,i,o,w,t,a[N],b[N],q[N],v[N<<1],f[N],g[N];
inline bool cmp(int x,int y){return a[x]+b[x]==a[y]+b[y]?a[x]<a[y]:a[x]+b[x]<a[y]+b[y];}
inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';}
void NIE(){puts("NIE");exit(0);}
void check(int len){
  if(!len)return;
  for(int i=2;i<n;i++)if(abs(a[i]-b[i])!=len)return;
  puts("TAK");
  printf("1 %d %d\n",n,len);
  for(int i=2;i<n;i++){
    if(a[i]<b[i])printf("1 %d %d\n",i,a[i]);
    else printf("%d %d %d\n",n,i,b[i]);
  }
  exit(0);
}
int main(){
  read(n);
  for(i=2;i<n;i++)read(a[i]);
  for(i=2;i<n;i++)read(b[i]);
  if(n==2){
    puts("TAK");
    puts("1 2 1");
    return 0;
  }
  check(abs(a[2]-b[2]));
  for(i=1;i<n;i++)q[i]=i;
  sort(q+2,q+n,cmp);
  w=a[q[2]]+b[q[2]];
  for(o=2;o<n;o++)if(a[q[o]]+b[q[o]]!=w)break;
  o--;
  for(i=2;i<o;i++)if(a[q[i]]==a[q[i+1]])NIE();
  for(v[w]=n,i=1;i<=o;i++)v[a[q[i]]]=q[i];
  for(i=o+1;i<n;i++){
    t=a[q[i]]+b[q[i]]-w;
    if(t&1)NIE();
    t>>=1;
    f[i]=v[a[q[i]]-t],g[i]=t;
    if(!f[i])NIE();
  }
  puts("TAK");
  for(i=2;i<=o;i++)printf("%d %d %d\n",q[i-1],q[i],a[q[i]]-a[q[i-1]]);
  printf("%d %d %d\n",q[o],n,b[q[o]]);
  for(;i<n;i++)printf("%d %d %d\n",q[i],f[i],g[i]);
  return 0;
}

  

posted @ 2017-12-02 02:14 Claris 阅读(...) 评论(...) 编辑 收藏