/*--------------------------------------------
two pointer 失败案例!
我们知道,two pointer它实际上,可以快速的求到
一串数字中任意两数之和的各种统计类问题。但是
这种统计具有局限性,即它不能附带任何附加条件。
比如说,这个程序,要求求满足两点间距离小于E且
大于S的这个距离的最短值。
我使用的算法是退化版的点分.我在处理每个子树的
时候用到了two pointer,希望用它来计算点u 的子
树中任意两点经过u的路径长度,但是实际上为了避
免v->u->v这种尴尬路径的存在,我使用了并查集判
掉了lf和rg属于同一棵子树的情况,并直接使rg--继
续判断。
但是这样是不行的,因为lf->u->(rg-1)的路径可能
并不比(lf+1)->u->rg优,这样的话,一旦我们走错
正确答案就没法更新到ans上,就会导致错误
因此,这个程序在某些数据下会出错。解决办法是,
在每个子树dfs完之后,sort一遍,并把u下已经dfs
过的其他也sort一遍,令lf在其他部分,rg在当前子
树部分,进行two pointer求和操作。这样就消除了
原本存在的附加条件。不过.这样带来的时间复杂度
也是十分庞大的,因为每个子树需要sort两遍,因此
总复杂度翻倍。可以适当优化常数
--------------------------------------------*/
#include <ctime>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std ;
struct Path{
int pre , to , len ;
}p[400005];
struct Data{
int id;long long dep ;
inline bool operator < (const Data &A ) const{
return dep < A.dep ;
}
}d[200005];
int N ,m, S , E , head[200005] , tp , fa[200005] , fffa[100005] ;
long long ans = 21474836464994545LL;
inline void In( int t1 , int t2 , int t3 ){
p[++tp].pre = head[t1] ;
p[tp].to = t2 ;
p[tp].len = t3 ;
head[t1] = tp ;
}
inline int find( int x ){
return fa[x] == x ? x : fa[x] = find( fa[x] ) ;
}
int root,sz[200005],mx[200005]={2147483646};
inline void dfsroot(int u,int fa){
sz[u]=1;
for(register int v,i=head[u];i;i=p[i].pre){
if(v=p[i].to,v!=fa){
dfsroot(v,u),sz[u]+=sz[v];
mx[u]=max(sz[v],mx[u]);
}
}
mx[u]=max(mx[u],m-sz[u]);
if(mx[u]<mx[root])root=u;
}
int in[200005] , out[200005] , dfs_c ;
inline void dfs( int u , int f ){
fffa[u] = f ;
in[u] = ++dfs_c ;
d[in[u]].id = u ;
long long nowd = d[in[u]].dep ;
for(register int i = head[u] ; i ; i = p[i].pre ){
int v = p[i].to ;
if( v != f ){
d[dfs_c+1].dep = nowd + p[i].len ;
dfs( v , u ) ;
}
}
out[u] = dfs_c ;
int lf = in[u] , rg = out[u] ;
sort( d+lf+1 , d+rg+1 ) ;
while( lf != rg ){
long long len = d[lf].dep + d[rg].dep - 2*nowd ;
if( len < S )
lf ++ ;
else if( len > E )
rg -- ;
else{
if( find(d[lf].id) != find(d[rg].id) )
ans = min(ans , len ) ;
rg -- ;
}
}
for(register int i = head[u] ; i ; i = p[i].pre ){
int v = p[i].to ;
if( v != f ) fa[v] = u;
}
}
template<class T>inline void read(T &res){
static char ch;T flag=1;
while((ch=getchar())<'0'||ch>'9')if(ch=='-')flag=-1;res=ch-48;
while((ch=getchar())>='0'&&ch<='9')res=res*10+ch-48;res*=flag;
}
int main(){
freopen( "B7.in" , "r" , stdin ) ;
//freopen( "path.out", "w" , stdout) ;
int t1 , t2 , t3 ;
scanf( "%d%d%d" , &N , &S , &E ) ;
for(register int i = 1 ; i < N ; ++i ){
read(t1) , read(t2) , read(t3) ;
In( t1 , t2 , t3 ) ;In( t2 , t1 , t3 ) ;
fa[i] = i ;
}
fa[N] = N ;
m=N,dfsroot(1,0);
dfs(root, 0 ) ;
//dfs(N/2+1,0);
printf("%I64d",(ans == 21474836464994545LL ?
修改之后的代码:
其实这个方法是过不了链状数据和菊花图数据的
只是因为这边数据是随机的,反而正规的二分check+点分还要快
#include <ctime>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std ;
struct Path{
int pre , to , len ;
}p[400005];
struct Data{
int id , dep ;
inline bool operator < (const Data &A ) const{
return dep < A.dep ;
}
}d[200005];
int N ,m, S , E , head[200005] , tp , fa[200005] , ans = 2147483646 ;
inline void In( int t1 , int t2 , int t3 ){
p[++tp].pre = head[t1] ;
p[tp].to = t2 ;
p[tp].len = t3 ;
head[t1] = tp ;
}
int in[200005] , out[200005] , dfs_c ;
inline void dfs( int u , int f ){
in[u] = ++dfs_c ;
d[in[u]].id = u ;
int nowd = d[in[u]].dep ;
for(register int i = head[u] ; i ; i = p[i].pre ){
int v = p[i].to ;
if( v != f ){
d[dfs_c+1].dep = nowd + p[i].len ;
dfs( v , u ) ;
sort( d+in[u]+1 , d+in[v] ) ;
sort( d+in[v]+1 , d+out[v]+1 ) ;
int lf = in[u] , rg = out[v] ;
while( lf < in[v] && rg >= in[v] ){
int len = d[lf].dep + d[rg].dep - 2 * nowd ;
if( len < S ) lf ++ ;
else{
ans = min( ans , len ) ;
rg -- ;
}
}
}
}
out[u] = dfs_c ;
}
template<class T>inline void read(T &res){
static char ch;T flag=1;
while((ch=getchar())<'0'||ch>'9')if(ch=='-')flag=-1;res=ch-48;
while((ch=getchar())>='0'&&ch<='9')res=res*10+ch-48;res*=flag;
}
int main(){
freopen( "path.in" , "r" , stdin ) ;
freopen( "path.out", "w" , stdout) ;
int t1 , t2 , t3 ;
scanf( "%d%d%d" , &N , &S , &E ) ;
for(register int i = 1 ; i < N ; ++i ){
read(t1) , read(t2) , read(t3) ;
In( t1 , t2 , t3 ) ;In( t2 , t1 , t3 ) ;
}
dfs(N/2+1,0);
printf("%d",(ans > E ? -1 : ans ) );
return 0;
}