1. 程式人生 > >[BZOJ5100][POI2018]Plan metra(構造)

[BZOJ5100][POI2018]Plan metra(構造)

若1與n直接相連,則所有點到1與n的距離差的絕對值是相同的,根據距離選擇與1還是n直接相連即可。

若不直接相連,則其餘所有點到1與n的距離和的最小值就是1到n的距離。

找到所有在1到n的路徑上的點,按與1的距離排序,然後相鄰的兩兩連邊。其餘點算出應該掛在鏈上哪個點下面,注意判斷各種不合法即可。

 1 #include<cstdio>
 2 #include<algorithm>
 3 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
 4 typedef long long ll;
 5 using
namespace std; 6 7 const int N=1000010; 8 int n,a[N],b[N],id[N]; 9 struct P{ int x,i; }d[N]; 10 bool operator <(const P &a,const P &b){ return a.x<b.x; } 11 12 int main(){ 13 freopen("bzoj5100.in","r",stdin); 14 freopen("bzoj5100.out","w",stdout); 15 scanf("%d",&n);
16 rep(i,2,n-1) scanf("%d",&a[i]); 17 rep(i,2,n-1) scanf("%d",&b[i]); 18 if (n==2){ printf("TAK\n1 2 1\n"); return 0; } 19 int len=abs(a[2]-b[2]); 20 rep(i,3,n-1) if (abs(a[i]-b[i])!=len){ len=0; break; } 21 if (len){ 22 puts("TAK"); printf("1 %d %d\n",n,len);
23 rep(i,2,n-1) 24 if (a[i]>b[i]) printf("%d %d %d\n",i,n,b[i]); 25 else printf("%d %d %d\n",i,1,a[i]); 26 return 0; 27 } 28 len=2000000; int tot=0; 29 rep(i,2,n-1) len=min(len,a[i]+b[i]); 30 rep(i,2,n) if (a[i]+b[i]==len) d[++tot]=(P){a[i],i}; 31 sort(d+1,d+tot+1); d[0]=(P){0,1}; d[++tot]=(P){len,n}; 32 rep(i,1,tot) if (d[i].x==d[i-1].x){ puts("NIE"); return 0; } 33 rep(i,0,tot) id[d[i].x]=d[i].i; 34 rep(i,2,n-1) if (a[i]+b[i]>len && (((a[i]+b[i]-len)&1) || !id[a[i]-(a[i]+b[i]-len)/2])){ puts("NIE"); return 0; } 35 puts("TAK"); 36 rep(i,1,tot) printf("%d %d %d\n",d[i-1].i,d[i].i,d[i].x-d[i-1].x); 37 rep(i,2,n-1) if (a[i]+b[i]>len) printf("%d %d %d\n",id[a[i]-(a[i]+b[i]-len)/2],i,(a[i]+b[i]-len)/2); 38 return 0; 39 }