1. 程式人生 > >bzoj5100 [POI2018]Plan metra 構造

bzoj5100 [POI2018]Plan metra 構造

ret gen online pro style size har red n)

5100: [POI2018]Plan metra

Time Limit: 40 Sec Memory Limit: 128 MBSec Special Judge
Submit: 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

7
6 6 2 2 1
5 3 5 1 4

Sample Output

TAK
1 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 構造