掉坑记录--two pointer

来源:互联网 发布:android studio 源码 编辑:程序博客网 时间:2024/05/17 12:53
/*--------------------------------------------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;}