bzoj 1171 并查集优化顺序枚举 | 线段树套单调队列
详见vfleaking在discuss里的题解.
收获: 当我们要顺序枚举一个序列,并且跳过某些元素,那么我们可以用并查集将要跳过的元素合并到一起,这样当一长串元素需要跳过时,可以O(1)跳过.
暴力:
1 /************************************************************** 2 Problem: 1171 3 User: idy002 4 Language: C++ 5 Result: Accepted 6 Time:1908 ms 7 Memory:6732 kb 8 ****************************************************************/ 9 10 #include <cstdio> 11 #include <cstring> 12 #define min(a,b) ((a)<(b)?(a):(b)) 13 #define max(a,b) ((a)>(b)?(a):(b)) 14 #define oo 0x3f3f3f3f 15 #define N 250010 16 17 int n, L; 18 int x[N], y[N], d[N]; 19 int dp[N], fa[N], qu[N], bg, ed; 20 21 int find( int i ) { 22 return i==fa[i] ? i : fa[i]=find(fa[i]); 23 } 24 int main() { 25 scanf( "%d%d", &n, &L ); 26 d[1] = 0; 27 x[1] = 0; 28 y[1] = 2000000000; 29 for( int i=2; i<=n; i++ ) 30 scanf( "%d%d%d", x+i, y+i, d+i ); 31 for( int i=1; i<=n; i++ ) 32 fa[i] = i; 33 memset( dp, 0x3f, sizeof(dp) ); 34 35 dp[1] = 0; 36 qu[bg=ed=1] = 1; 37 while( bg<=ed ) { 38 int i=qu[bg++]; 39 for( int j=find(i)+1; j<=n && d[j]-d[i]<=L; j=find(j)+1 ) { 40 if( dp[j]!=oo ) continue; 41 int xx = max( x[i], x[j] ); 42 int yy = min( y[i], y[j] ); 43 if( xx<=yy ) { 44 dp[j] = dp[i]+1; 45 qu[++ed] = j; 46 if( dp[j-1]!=oo ) fa[j-1]=j; 47 if( dp[j+1]!=oo ) fa[j]=j+1; 48 } 49 } 50 } 51 for( int i=2; i<=n; i++ ) 52 printf( "%d\n", dp[i]==oo ? -1 : dp[i] ); 53 }
线段树套单调队列:
1 #include <cstdio> 2 #include <list> 3 #include <algorithm> 4 #define N 250010 5 #define oo 0x3f3f3f3f 6 using namespace std; 7 8 struct Pair { 9 int d, v; 10 Pair( int d, int v ):d(d),v(v){} 11 }; 12 struct Queue { 13 list<Pair> q; 14 void push( const Pair &p ) { 15 while( !q.empty() && q.back().v >= p.v ) q.pop_back(); 16 q.push_back( p ); 17 } 18 int pop( int d ) { 19 while( !q.empty() && q.front().d<d ) q.pop_front(); 20 return q.empty() ? oo : q.front().v; 21 } 22 }; 23 struct Node { 24 Queue qa, qb; 25 int lf, rg; 26 Node *ls, *rs; 27 void modify( int L, int R, const Pair &p ) { 28 qb.push(p); 29 if( L<=lf && rg<=R ) { 30 qa.push(p); 31 return; 32 } 33 int mid=(lf+rg)>>1; 34 if( L<=mid ) ls->modify(L,R,p); 35 if( R>mid ) rs->modify(L,R,p); 36 } 37 int query( int L, int R, int d ) { 38 if( L<=lf && rg<=R ) return qb.pop(d); 39 int rt = qa.pop(d); 40 int mid=(lf+rg)>>1; 41 if( L<=mid ) { 42 int t = ls->query(L,R,d); 43 rt = min( rt, t ); 44 } 45 if( R>mid ) { 46 int t = rs->query(L,R,d); 47 rt = min( rt, t ); 48 } 49 return rt; 50 } 51 }pool[N*2*3], *tail=pool, *root; 52 53 int n, L; 54 int x[N], y[N], d[N]; 55 int disc[N*2], dtot; 56 57 Node *build( int lf, int rg ) { 58 Node *nd = ++tail; 59 nd->lf=lf, nd->rg=rg; 60 if( lf==rg ) { 61 return nd; 62 } else { 63 int mid=(lf+rg)>>1; 64 nd->ls = build( lf, mid ); 65 nd->rs = build( mid+1, rg ); 66 return nd; 67 } 68 } 69 int main() { 70 scanf( "%d%d", &n, &L ); 71 x[1] = 0; 72 y[1] = 2000000000; 73 disc[++dtot] = x[1]; 74 disc[++dtot] = y[1]; 75 d[1] = 0; 76 for( int i=2; i<=n; i++ ) { 77 scanf( "%d%d%d", x+i, y+i, d+i ); 78 disc[++dtot] = x[i]; 79 disc[++dtot] = y[i]; 80 } 81 sort( disc+1, disc+1+dtot ); 82 dtot = unique( disc+1, disc+1+dtot ) - disc - 1; 83 for( int i=1; i<=n; i++ ) { 84 x[i] = lower_bound( disc+1, disc+1+dtot, x[i] ) - disc; 85 y[i] = lower_bound( disc+1, disc+1+dtot, y[i] ) - disc; 86 } 87 root = build( 1, dtot ); 88 root->modify( x[1], y[1], Pair(0,0) ); 89 for( int i=2; i<=n; i++ ) { 90 int ans = root->query( x[i], y[i], d[i]-L ); 91 if( ans==oo ) { 92 printf( "-1\n" ); 93 } else { 94 ans++; 95 printf( "%d\n", ans ); 96 root->modify( x[i], y[i], Pair(d[i],ans) ); 97 } 98 } 99 }