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; }