掉坑记录--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;}
阅读全文
0 0
- 掉坑记录--two pointer
- Two-pointer technique
- [Algorithm]九章七:Two Pointer
- 11572 - Unique Snowflakes(two pointer)
- 【two-pointer】Codeforces762C[Two strings]题解
- The two-dimensional pointer operation in C++
- 11536 - Smallest Sub-Array (two pointer)
- CF-395A1 Skis (two pointer)
- String two pointer swapping (合集)
- LeetCode Minimum Window Substring(two pointer)
- [POJ 2100] Graveyard Design (Two Pointer)
- LeetCode 16. 3Sum Closest (Two-Pointer)
- Copy List with Random Pointer(two pointers)
- [two-pointer ST表] HDU5289: Assignment
- leetcode记录-Two Sum
- Copy List with Random Pointer & Add Two Numbers & Valid Palindrome
- 076.Pointer Two Array 指向多维数组的指针
- 076.Pointer Two Array 指向多维数组的指针
- fgthgffgjg吃的风格的风格
- number number number hdu 6189 矩阵快速幂
- 前端之常用库与框架
- 1072: 青蛙爬井
- sprigboot的配置文件
- 掉坑记录--two pointer
- equals与==背后的装箱拆箱机制
- Spark计算相关性系数(皮尔森、斯皮尔曼、卡方检验)
- 搜索引擎开发(1)资料收集
- jQuery动画
- PAT甲级1002. A+B for Polynomials (25)
- bzoj2152点分治
- springmvc 简单的注解
- windows 下Python 安装Pillow