bzoj5100 [POI2018]Plan metra 構造
阿新 • • 發佈:2017-12-27
ret gen online pro style size har red n)
Submit: 189 Solved: 43
[Submit][Status][Discuss]
6 6 2 2 1
5 3 5 1 4
1 5 2
5 7 1
5 2 4
7 3 3
1 4 2
1 6 1
如果是這種情況,那麽就有:對於任意一個點 i 1<i<n i到1與n的距離之差為一個定值a,a=1到n的邊權
特判一下 每個點到 1和n的距離差是否相等就好
如果相等,可以直接把1和n相連 其它點都與1和n相連
如果不等,進入第二種情況
/2是因為計算了2次 而如果w不能被整除的話,點i不能鏈接到樹上
5100: [POI2018]Plan metra
Time Limit: 40 Sec Memory Limit: 128 MBSec Special JudgeSubmit: 189 Solved: 43
[Submit][Status][Discuss]
Description
有一棵n個點的無根樹,每條邊有一個正整數權值,表示長度,定義兩點距離為在樹上的最短路徑的長度。 已知2到n-1每個點在樹上與1和n的距離,請根據這些信息還原出這棵樹。
Input
第一行包含一個正整數n(2<=n<=500000),表示點數。 第二行包含n-2個正整數d(1,2),d(1,3),...,d(1,n-1),分別表示每個點到1的距離。 第三行包含n-2個正整數d(n,2),d(n,3),...,d(n,n-1),分別表示每個點到n的距離。 輸入數據保證1<=d<=1000000。
Output
若無解,輸出NIE。 否則第一行輸出TAK,接下來n-1行每行三個正整數u,v,c(1<=u,v<=n,1<=c<=1000000) 表示存在一條長度為c的連接u和v兩點的樹邊。 若有多組解,輸出任意一組。
Sample Input
76 6 2 2 1
5 3 5 1 4
Sample Output
TAK1 5 2
5 7 1
5 2 4
7 3 3
1 4 2
1 6 1
HINT
Source
鳴謝Claris上傳試題
構造題
分情況討論
1. 1-n路徑上沒有其他點,即1與n直接相連
如果是這種情況,那麽就有:對於任意一個點 i 1<i<n i到1與n的距離之差為一個定值a,a=1到n的邊權
特判一下 每個點到 1和n的距離差是否相等就好
如果相等,可以直接把1和n相連 其它點都與1和n相連
如果不等,進入第二種情況
2. 1-n路徑上還有點
我們可以找出這些點 這些點有一個共性:它們 到1與n的距離和 相等 且 比 不在1-n路徑上的點 到1和n的距離和 小
找到這些點之後 其他點都可以通過與路徑上的點相連來構造答案
如果一個點i與路徑上某點相連 設它到1的距離為d1 到n的距離為dn
那麽它到路徑上某點(假設存在)的距離就是 w=(d1+dn-(1-n的距離))/2
/2是因為計算了2次 而如果w不能被整除的話,點i不能鏈接到樹上
再判斷路徑上這個點是否存在,如果路徑上不存在這個點,依舊沒法把點i鏈接到樹 判斷條件 : 到1距離為d1-w的點存在於路徑上
這樣就一定可以構造出一棵合法樹
#include<bits/stdc++.h> #define N 500005 using namespace std; int n,fg,mn=0x3f3f3f3f,fa[N],w[N],d1[N],dn[N],id[N<<2]; inline char gc(){ static char s[1000000],*p1,*p2; if(p1==p2)p2=(p1=s)+fread(s,1,1000000,stdin); if(p1==p2)return EOF;return *p1++; } inline int read(){ int x=0;char ch=gc(); while(ch<‘0‘||ch>‘9‘)ch=gc(); while(ch>=‘0‘&&ch<=‘9‘)x=x*10+ch-‘0‘,ch=gc(); return x; } inline int solve1(){ int dis=abs(d1[2]-dn[2]); if(!dis)return 0; for(register int i=3;i<n;++i) if(dis!=abs(d1[i]-dn[i]))return 0; puts("TAK");printf("%d %d %d\n",1,n,dis); for(register int i=2;i<n;++i){ if(d1[i]<dn[i])printf("%d %d %d\n",i,1,d1[i]); else printf("%d %d %d\n",i,n,dn[i]); } return 1; } int main(){ n=read();if(n==2){puts("TAK\n1 2 1");return 0;} for(register int i=2;i<n;++i)d1[i]=read(); for(register int i=2;i<n;++i){ dn[i]=read(); dn[i]+d1[i]<mn?mn=dn[i]+d1[i]:1; } if(solve1())return 0; id[mn]=n;id[0]=1; for(register int i=2;i<n&&!fg;++i){ if(dn[i]+d1[i]==mn){ if(id[d1[i]])fg=1; else id[d1[i]]=i; } } if(fg){puts("NIE");return 0;} for(register int i=2;i<n&&!fg;++i){ if(d1[i]+dn[i]==mn)continue; int tmp=d1[i],len=d1[i]+dn[i]-mn; if(len&1)fg=1;len>>=1; tmp-=len;if(!id[tmp])fg=1; fa[i]=id[tmp];w[i]=len; } if(fg){puts("NIE");return 0;} int pre=1;puts("TAK"); for(register int i=1;i<=mn;++i){ if(!id[i])continue; printf("%d %d %d\n",pre,id[i],i-d1[pre]); pre=id[i]; } for(register int i=2;i<n;++i){ if(!fa[i])continue; printf("%d %d %d\n",i,fa[i],w[i]); } return 0; }
bzoj5100 [POI2018]Plan metra 構造