# bzoj 3999 线段树区间提取 有序链剖

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;
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 );
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 }
View Code

posted @ 2015-06-09 15:11  idy002  阅读(369)  评论(0编辑  收藏  举报