bzoj 3999 线段树区间提取 有序链剖
看错题目了,想成每个城市都可以买一个东西,然后在后面的某个城市卖掉,问最大收益.这个可以类似维护上升序列的方法在O(nlog^3n)的时间复杂度内搞定
这道题用到的一些方法:
1. 可以将有关的线段提取出来,然后一起处理.
2. 线段树可以维护两个方向的信息,这样就可以处理树上有序的东西.
1 /************************************************************** 2 Problem: 3999 3 User: idy002 4 Language: C++ 5 Result: Accepted 6 Time:3204 ms 7 Memory:12144 kb 8 ****************************************************************/ 9 10 #include <cstdio> 11 #include <cstring> 12 #include <algorithm> 13 #define max(a,b) ((a)>(b)?(a):(b)) 14 #define N 50010 15 using namespace std; 16 17 typedef long long dnt; 18 struct Node { 19 dnt t, b, a[2], tag; 20 int lf, rg; 21 Node *ls, *rs; 22 void pushdown() { 23 if( tag ) { 24 ls->t += tag; 25 ls->b += tag; 26 ls->tag += tag; 27 rs->t += tag; 28 rs->b += tag; 29 rs->tag += tag; 30 tag = 0; 31 } 32 } 33 void update() { 34 t = max( ls->t, rs->t ); 35 b = min( ls->b, rs->b ); 36 a[0] = max( ls->a[0], rs->a[0] ); 37 a[0] = max( a[0], rs->t-ls->b ); 38 a[1] = max( ls->a[1], rs->a[1] ); 39 a[1] = max( a[1], ls->t-rs->b ); 40 } 41 void modify( int L, int R, int d ) { 42 if( L<=lf && rg<=R ) { 43 t += d; 44 b += d; 45 tag += d; 46 return; 47 } 48 pushdown(); 49 int mid=(lf+rg)>>1; 50 if( L<=mid ) ls->modify( L, R, d ); 51 if( R>mid ) rs->modify( L, R, d ); 52 update(); 53 } 54 }pool[N*3], *tail=pool, *root; 55 56 int n, m; 57 int head[N], dest[N<<1], next[N<<1], etot; 58 int aa[N], bb[N]; 59 int fat[N], dep[N], siz[N], son[N], top[N], vid[N]; 60 int qu[N], bg, ed; 61 Node *su[N], *sv[N]; 62 int tu, tv; 63 64 void adde( int u, int v ) { 65 etot++; 66 dest[etot] = v; 67 next[etot] = head[u]; 68 head[u] = etot; 69 } 70 Node *build( int lf, int rg ) { 71 Node *nd = ++tail; 72 if( lf==rg ) { 73 nd->b = nd->t = bb[lf]; 74 nd->a[0] = nd->a[1] = 0; 75 nd->lf=lf, nd->rg=rg; 76 } else { 77 int mid=(lf+rg)>>1; 78 nd->ls = build( lf, mid ); 79 nd->rs = build( mid+1, rg ); 80 nd->lf=lf, nd->rg=rg; 81 nd->update(); 82 } 83 return nd; 84 } 85 void fetch( Node *nd, int L, int R, Node *(&stk)[N], int &top ) { 86 int lf=nd->lf, rg=nd->rg; 87 if( L<=lf && rg<=R ) { 88 stk[++top] = nd; 89 return; 90 } 91 int mid=(lf+rg)>>1; 92 nd->pushdown(); 93 if( R>mid ) fetch(nd->rs,L,R,stk,top); 94 if( L<=mid ) fetch(nd->ls,L,R,stk,top); 95 } 96 void build_dcp( int s ) { 97 // fat dep 98 fat[s] = 0; 99 dep[s] = 1; 100 qu[bg=ed=1] = s; 101 while( bg<=ed ) { 102 int u=qu[bg++]; 103 for( int t=head[u]; t; t=next[t] ) { 104 int v=dest[t]; 105 if( v==fat[u] ) continue; 106 fat[v] = u; 107 dep[v] = dep[u] + 1; 108 qu[++ed] = v; 109 } 110 } 111 // siz son 112 for( int i=ed; i>=1; i-- ) { 113 int u=qu[i], p=fat[u]; 114 siz[u]++; 115 if( p ) { 116 siz[p] += siz[u]; 117 if( siz[u]>siz[son[p]] ) son[p]=u; 118 } 119 } 120 // top vid 121 top[s] = s; 122 vid[s] = 1; 123 for( int i=1; i<=ed; i++ ) { 124 int u=qu[i]; 125 int cur=vid[u]+1; 126 if( son[u] ) { 127 top[son[u]] = top[u]; 128 vid[son[u]] = cur; 129 cur += siz[son[u]]; 130 } 131 for( int t=head[u]; t; t=next[t] ) { 132 int v=dest[t]; 133 if( v==fat[u] || v==son[u] ) continue; 134 top[v] = v; 135 vid[v] = cur; 136 cur += siz[v]; 137 } 138 } 139 // segment 140 for( int i=1; i<=n; i++ ) 141 bb[vid[i]] = aa[i]; 142 root = build( 1, n ); 143 } 144 int lca( int u, int v ) { 145 while( top[u]!=top[v] ) { 146 if( dep[top[u]]<dep[top[v]] ) swap(u,v); 147 u = fat[top[u]]; 148 } 149 return dep[u]<dep[v] ? u : v; 150 } 151 dnt query( int u, int v ) { 152 if( u==v ) return 0; 153 int ca = lca(u,v); 154 tu = tv = 0; 155 while( top[u]!=top[ca] ) { 156 fetch(root,vid[top[u]],vid[u],su,tu); 157 u=fat[top[u]]; 158 } 159 while( top[v]!=top[ca] ) { 160 fetch(root,vid[top[v]],vid[v],sv,tv); 161 v=fat[top[v]]; 162 } 163 if( u!=ca ) 164 fetch(root,vid[ca],vid[u],su,tu); 165 else 166 fetch(root,vid[ca],vid[v],sv,tv); 167 dnt curt = 0; 168 dnt rt = 0; 169 for( int i=1; i<=tv; i++ ) { 170 rt = max( rt, sv[i]->a[0] ); 171 rt = max( rt, curt-sv[i]->b ); 172 curt = max( curt, sv[i]->t ); 173 } 174 for( int i=tu; i>=1; i-- ) { 175 rt = max( rt, su[i]->a[1] ); 176 rt = max( rt, curt-su[i]->b ); 177 curt = max( curt, su[i]->t ); 178 } 179 return rt; 180 } 181 void modify( int u, int v, int d ) { 182 while( top[u]!=top[v] ) { 183 if( dep[top[u]]<dep[top[v]] ) swap(u,v); 184 root->modify(vid[top[u]],vid[u],d); 185 u=fat[top[u]]; 186 } 187 if( dep[u]<dep[v] ) swap(u,v); 188 root->modify(vid[v],vid[u],d); 189 } 190 int main() { 191 scanf( "%d", &n ); 192 for( int i=1; i<=n; i++ ) 193 scanf( "%d", aa+i ); 194 for( int i=1,u,v; i<n; i++ ) { 195 scanf( "%d%d", &u, &v ); 196 adde( u, v ); 197 adde( v, u ); 198 } 199 build_dcp(1); 200 scanf( "%d", &m ); 201 for( int t=1,u,v,d; t<=m; t++ ) { 202 scanf( "%d%d%d", &u, &v, &d ); 203 printf( "%lld\n", query(u,v) ); 204 modify(u,v,d); 205 } 206 }