[BZOJ2117]Crash的旅游计划
Description
眼看着假期就要到了,Crash由于长期切题而感到无聊了,因此他决定利用这个假期和好友陶陶一起出去旅游。
Crash和陶陶所要去的城市里有N (N > 1) 个景点,Crash用正整数1到N给景点标号。
这些景点之间通过N - 1条无向道路相连,每条道路有一个长度,并且保证任意两个景点之间都有且仅有一条路径相连。
现在对于一个景点s,Crash和陶陶从s出发,然后访问一个景点序列{v0, v1, v2, … , vk},
其中v0就是s,且vi-1和vi(0 < i ≤ k)之间有道路相连。
需要注意的是,陶陶和Crash访问的景点序列中不会只有景点s。
为了使旅程不显得乏味,在一个景点序列里他们不会重复走某条道路。
我们定义这个序列的旅游代价为经过道路的长度和。下面问题出现了:
陶陶:我们走一条景点数最多的景点序列吧。
Crash:倒,你想把我累死啊。
陶陶:谁叫你整天坐在电脑前面,不出来锻炼,这下子傻了吧,哈哈哈哈~~
Crash:不行,如果你非要走景点数最多的我就不陪你走了。
陶陶:笑喷油你很跳嘛!
Crash:这样吧,我们来写伸展树,如果我写的比你快,你就要听我的。
陶陶:这样不公平哎,我们来玩PES吧,当然你要让我选法国队,如果你输了你就要听我的。
Crash:倒,你这是欺负我,T_T~
陶陶:笑喷油好说话哎。
Crash:囧……
……
这样搞了半天,最终陶陶和Crash用很多次包剪锤决定出选择旅游代价第K小 的景点序列。
不过呢Crash和陶陶还没确定开始旅行的景点s,因此他希望你对于每个景点i,计算从景点i开始的景点序列中旅游代价第K小的值。
Input
共N行。
第1行包含一个字符和两个正整数,字符为ABCD中的一个,用来表示这个测试数据的类型
(详见下面的数据规模和约定),另外两个正整数分别表示N和K (K < N),N<=100000
第2行至第N行,每行有三个正整数u、v和w (u, v ≤ N,w ≤ 10000)。
表示u号景点和v号景点之间有一条道路,长度为w。
输入文件保证符合题目的约定,即任意两个景点之间都有且仅有一条路径相连。
Output
共N行,每行有一个正整数。
第i行的正整数表示从i号景点开始的景点序列中旅游代价第K小的代价。
Sample Input
A 6 3
1 2 2
1 3 4
1 4 3
3 5 1
3 6 2
1 2 2
1 3 4
1 4 3
3 5 1
3 6 2
Sample Output
4
6
4
7
5
6
//样例1中输出对应的景点序列分别为:
1号景点是{1, 3},2号景点是{2, 1, 3},3号景点是{3, 1},4号景点是{4, 1, 3},5号景点是{5, 3, 1},6号景点是{6, 3, 1}。
保证每个景点到1号景点需要经过的道路数不超过30
6
4
7
5
6
//样例1中输出对应的景点序列分别为:
1号景点是{1, 3},2号景点是{2, 1, 3},3号景点是{3, 1},4号景点是{4, 1, 3},5号景点是{5, 3, 1},6号景点是{6, 3, 1}。
保证每个景点到1号景点需要经过的道路数不超过30
二分答案,然后点分树上二分$vector$判定
代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<vector> 5 #include<algorithm> 6 #define M 100010 7 using namespace std; 8 int n,m,num,S,root,k; 9 int deep[M],f[M],fa[M],sz[M],size[M]; 10 int head[M],dis[M],son[M],maxn[M],top[M]; 11 bool vis[M]; 12 struct point{int to,next,dis;}e[M<<1]; 13 vector<int>S1[M],S2[M]; 14 void add(int from,int to,int dis) { 15 e[++num].next=head[from]; 16 e[num].to=to; 17 e[num].dis=dis; 18 head[from]=num; 19 } 20 void dfs1(int x) { 21 deep[x]=deep[f[x]]+1,sz[x]=1; 22 for(int i=head[x];i;i=e[i].next) { 23 int to=e[i].to; 24 if(to==f[x]) continue; 25 f[to]=x,dis[to]=dis[x]+e[i].dis; 26 dfs1(to),sz[x]+=sz[to]; 27 if(sz[son[x]]<sz[to]) son[x]=to; 28 } 29 } 30 void dfs2(int x,int tp) { 31 top[x]=tp; 32 if(son[x]) dfs2(son[x],tp); 33 for(int i=head[x];i;i=e[i].next) 34 if(e[i].to!=f[x]&&e[i].to!=son[x]) 35 dfs2(e[i].to,e[i].to); 36 } 37 int lca(int x,int y) { 38 while(top[x]!=top[y]) { 39 if(deep[top[x]]<deep[top[y]]) swap(x,y); 40 x=f[top[x]]; 41 } 42 return deep[x]<deep[y]?x:y; 43 } 44 int getdis(int x,int y) { 45 return dis[x]+dis[y]-2*dis[lca(x,y)]; 46 } 47 void getroot(int x,int fa) { 48 size[x]=1;maxn[x]=0; 49 for(int i=head[x];i;i=e[i].next) { 50 int to=e[i].to; 51 if(fa==to||vis[to]) continue; 52 getroot(to,x);size[x]+=size[to]; 53 maxn[x]=max(maxn[x],size[to]); 54 } 55 maxn[x]=max(maxn[x],S-size[x]); 56 if(maxn[x]<maxn[root]) root=x; 57 } 58 void solve(int x,int ff) { 59 fa[x]=ff;vis[x]=true; 60 for(int i=head[x];i;i=e[i].next) { 61 int to=e[i].to; 62 if(vis[to]) continue; 63 S=size[to],root=0,getroot(to,x); 64 solve(root,x); 65 } 66 } 67 void update(int x) { 68 S1[x].push_back(0); 69 for(int i=x;fa[i];i=fa[i]) { 70 int dt=getdis(x,fa[i]); 71 S1[fa[i]].push_back(dt); 72 S2[i].push_back(dt); 73 } 74 } 75 int get1(int id,int d) { 76 int l=0,r=S1[id].size()-1,ans=0; 77 while(l<=r) { 78 int mid=(l+r)/2; 79 if(S1[id][mid]<=d) l=mid+1,ans=mid+1; 80 else r=mid-1; 81 } 82 return ans; 83 } 84 int get2(int id,int d) { 85 int l=0,r=S2[id].size()-1,ans=0; 86 while(l<=r) { 87 int mid=(l+r)/2; 88 if(S2[id][mid]<=d) l=mid+1,ans=mid+1; 89 else r=mid-1; 90 } 91 return ans; 92 } 93 int query(int x,int d) { 94 int ans=get1(x,d); 95 for(int i=x;fa[i];i=fa[i]) { 96 int dt=getdis(fa[i],x); 97 if(dt>d) continue; 98 ans+=get1(fa[i],d-dt); 99 ans-=get2(i,d-dt); 100 } 101 return ans; 102 } 103 int main() { 104 char s[10];scanf("%s",s); 105 scanf("%d%d",&n,&k);k++; 106 for(int i=1;i<n;i++) { 107 int a,b,c;scanf("%d%d%d",&a,&b,&c); 108 add(a,b,c),add(b,a,c); 109 } 110 dfs1(1),dfs2(1,1); 111 maxn[0]=S=n,getroot(1,0),solve(root,0); 112 for(int i=1;i<=n;i++) 113 update(i); 114 for(int i=1;i<=n;i++) { 115 if(!S1[i].empty()) sort(S1[i].begin(),S1[i].end()); 116 if(!S2[i].empty()) sort(S2[i].begin(),S2[i].end()); 117 } 118 for(int i=1;i<=n;i++) { 119 int l=0,r=1e9,ans=1e9; 120 while(l<=r) { 121 int mid=(l+r)/2; 122 if(query(i,mid)>=k) ans=mid,r=mid-1; 123 else l=mid+1; 124 } 125 printf("%d\n",ans); 126 } 127 return 0; 128 }