[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 }

 

posted @ 2018-04-05 13:00  skylee03  阅读(102)  评论(0编辑  收藏  举报