[POI2018]Plan metra
题目大意:
一棵$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 }