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

[POI2018]Plan metra

位置 str NPU rac amp clu con input 發現

題目大意:
  一棵$n(n\le5\times10^5)$個結點的樹,每條邊的邊權均為正整數,告訴你$2\sim n-1$號結點到$1$號點和$n$號點的距離$d1[i]$和$d2[i]$。求是否存在這樣的樹,若存在,則構造出這樣一棵樹。

思路:
  若對於所有的$1<i<n$,$|d1[i]-d2[i]|$都相等,則$1$與$n$直接相連,其余點與$1$和$n$中最近的點相連。
  否則若存在這樣的樹,肯定能構造出一種方案,使得$d1[n]=\min\{d1[i]+d2[i]\}$。令$d=\min\{d1[i]+d2[i]\}$,若點$i$滿足$d1[i]+d2[i]=d$,則$i$一定在$1$到$n$的鏈上。通過排序可以求出$1$到$n$的鏈,如果發現有兩點在同一位置,則構造失敗。對於剩下的點$i$,向滿足$d1[j]=d-\frac{d1[i]-d2[i]+d}2$的點$j$連一條長度為$d1[i]-d1[j]$的邊即可,如果不存在這樣的點$j$,則構造失敗,若新建邊長度不為正整數則還是構造失敗。

 1 #include<cstdio>
 2 #include<cctype>
 3 #include<algorithm>
 4 #include<sys/mman.h>
 5 #include<sys/stat.h>
 6 class MMapInput {
 7     private:
 8         char *buf,*p;
 9         int size;
10     public:
11         MMapInput() {
12             register int
fd=fileno(stdin); 13 struct stat sb; 14 fstat(fd,&sb); 15 size=sb.st_size; 16 buf=reinterpret_cast<char*>(mmap(0,size,PROT_READ,MAP_PRIVATE,fileno(stdin),0)); 17 p=buf; 18 } 19 char getchar() { 20 return
(p==buf+size||*p==EOF)?EOF:*p++; 21 } 22 }; 23 MMapInput mmi; 24 inline int getint() { 25 register char ch; 26 while(!isdigit(ch=mmi.getchar())); 27 register int x=ch^0; 28 while(isdigit(ch=mmi.getchar())) x=(((x<<2)+x)<<1)+(ch^0); 29 return x; 30 } 31 const int N=5e5+1,C=1e6; 32 int d1[N],d2[N],cnt,tmp[N],mem[C<<1],*vis=mem+C; 33 struct Edge { 34 int u,v,w; 35 }; 36 Edge e[N]; 37 inline bool cmp(const int &a,const int &b) { 38 return d1[a]<d1[b]; 39 } 40 int main() { 41 const int n=getint(); 42 if(n==2) { 43 puts("TAK\n1 2 1"); 44 return 0; 45 } 46 for(register int i=2;i<n;i++) d1[i]=getint(); 47 for(register int i=2;i<n;i++) d2[i]=getint(); 48 if(d1[2]!=d2[2]) { 49 for(register int i=3;i<n;i++) { 50 if(std::abs(d1[i]-d2[i])!=std::abs(d1[2]-d2[2])) goto case2; 51 } 52 e[cnt++]=(Edge){1,n,std::abs(d1[2]-d2[2])}; 53 for(register int i=2;i<n;i++) { 54 e[cnt++]=(Edge){i,d1[i]>d2[i]?n:1,std::min(d1[i],d2[i])}; 55 } 56 } else case2: { 57 int d=C*2; 58 for(register int i=2;i<n;i++) { 59 d=std::min(d,d1[i]+d2[i]); 60 } 61 d1[n]=d2[1]=d; 62 for(register int i=1;i<=n;i++) { 63 if(d1[i]+d2[i]==d) { 64 vis[d1[i]]=tmp[++tmp[0]]=i; 65 } 66 } 67 std::sort(&tmp[1],&tmp[tmp[0]]+1,cmp); 68 for(register int i=2;i<=tmp[0];i++) { 69 if(d1[tmp[i]]==d1[tmp[i-1]]) { 70 puts("NIE"); 71 return 0; 72 } 73 e[cnt++]=(Edge){tmp[i-1],tmp[i],d1[tmp[i]]-d1[tmp[i-1]]}; 74 } 75 for(register int i=1;i<=n;i++) { 76 if(d1[i]+d2[i]==d) continue; 77 const int j=vis[(d1[i]-d2[i]+d)/2]; 78 if((d1[i]+d2[i]-d)%2||!j) { 79 puts("NIE"); 80 return 0; 81 } 82 e[cnt++]=(Edge){j,i,d1[i]-d1[j]}; 83 } 84 } 85 puts("TAK"); 86 for(register int i=0;i<cnt;i++) { 87 printf("%d %d %d\n",e[i].u,e[i].v,e[i].w); 88 } 89 return 0; 90 }

[POI2018]Plan metra