spoj 375 query on a tree LCT
这道题是树链剖分的裸题,正在学LCT,用LCT写了,发现LCT代码比树链剖分还短点(但我的LCT跑极限数据用的时间大概是kuangbin大神的树链剖分的1.6倍,所以在spoj上是850ms卡过的)。
收获:
1、边转换成点(即若存在边(u,v),则新加一个点z代表边,将z连接u和v,z的点权就是(u,v)的边权,非边点的权设为-oo),然后对边权的统计就变成了对点权的统计(这是LCT中处理边信息的通法之一)。
2、若要连接两个点u,v,先让它们分别称为根,然后将其中一个的path-parent设为另一个。
3、若要查找(u,v)的边点,运用“夹逼法”,先让两个点在一条重链上(即同一棵splay树),再splay(u,0)和splay(v,u),这样v的一个子树就是边点(具体来说,可以先让u成为根,再access(v),splay(u,0),splay(v,u),此时v的左儿子必定是边点)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <cstdio> 2 #include <iostream> 3 #define maxn 20010 4 #define oo 0x3f3f3f3f 5 #define max(a,b) ((a)>(b)?(a):(b)) 6 using namespace std; 7 8 struct LCT { 9 int pnt[maxn], pre[maxn], son[maxn][2], val[maxn], mxv[maxn], ntot; 10 bool tag[maxn]; 11 12 inline void update( int nd ) { 13 mxv[nd] = max( val[nd], max( mxv[son[nd][0]], mxv[son[nd][1]] ) ); 14 } 15 void rotate( int nd, int d ) { 16 int p = pre[nd]; 17 int s = son[nd][!d]; 18 int ss = son[s][d]; 19 20 son[nd][!d] = ss; 21 son[s][d] = nd; 22 if( p ) son[p][ nd==son[p][1] ] = s; 23 else pnt[s] = pnt[nd]; 24 25 pre[nd] = s; 26 pre[s] = p; 27 if( ss ) pre[ss] = nd; 28 29 update( nd ); 30 update( s ); 31 } 32 inline void pushdown( int nd ) { 33 if( tag[nd] ) { 34 int &ls = son[nd][0], &rs = son[nd][1]; 35 swap( ls, rs ); 36 tag[ls] ^= 1; 37 tag[rs] ^= 1; 38 tag[nd] = 0; 39 } 40 } 41 void splay( int nd, int top=0 ) { 42 static int stk[maxn], spt; 43 int u = nd; 44 for( spt=0; u; u=pre[u] ) 45 stk[spt++] = u; 46 while( spt-- ) 47 pushdown( stk[spt] ); 48 while( pre[nd]!=top ) { 49 int p = pre[nd]; 50 int nl = nd==son[p][0]; 51 if( pre[p]==top ) { 52 rotate( p, nl ); 53 } else { 54 int pp = pre[p]; 55 int pl = p==son[pp][0]; 56 if( nl==pl ) { 57 rotate( pp, pl ); 58 rotate( p, nl ); 59 } else { 60 rotate( p, nl ); 61 rotate( pp, pl ); 62 } 63 } 64 } 65 } 66 void init( int n ) { 67 for( int i=0; i<=n; i++ ) { 68 pre[i] = pnt[i] = son[i][0] = son[i][1] = tag[i] = 0; 69 mxv[i] = val[i] = -oo; 70 } 71 } 72 void access( int nd ) { 73 int u = nd; 74 int v = 0; 75 while( u ) { 76 splay( u ); 77 int s = son[u][1]; 78 pre[s] = 0; 79 pnt[s] = u; 80 pre[v] = u; 81 son[u][1] = v; 82 v = u; 83 u = pnt[u]; 84 } 85 splay( nd ); 86 } 87 void makeroot( int nd ) { 88 access( nd ); 89 tag[nd] ^= 1; 90 } 91 void link( int u, int v ) { 92 makeroot(u); 93 makeroot(v); 94 pnt[u] = v; 95 } 96 void modify( int e, int w ) { 97 splay(e); 98 val[e] = w; 99 update( e ); 100 } 101 int query( int u, int v ) { 102 makeroot(u); 103 access(v); 104 return max(val[v],mxv[son[v][0]]); 105 } 106 }; 107 108 int n; 109 LCT LT; 110 111 int main() { 112 int T; 113 scanf( "%d", &T ); 114 while( T-- ) { 115 scanf( "%d", &n ); 116 LT.init(n+n-1); 117 for( int i=1,u,v,w; i<n; i++ ) { 118 scanf( "%d%d%d", &u, &v, &w ); 119 LT.modify( n+i, w ); 120 LT.link( u, n+i ); 121 LT.link( v, n+i ); 122 } 123 while(1) { 124 char ch[10]; 125 scanf( "%s", ch ); 126 if( ch[0]=='Q' ) { 127 int u, v; 128 scanf( "%d%d", &u, &v ); 129 printf( "%d\n", LT.query(u,v) ); 130 } else if( ch[0]=='C' ) { 131 int e, w; 132 scanf( "%d%d", &e, &w ); 133 LT.modify( n+e, w ); 134 } else break; 135 } 136 } 137 }