bzoj 4127 线段树维护绝对值之和

 

因为d>=0,所以一个位置的数只会单调不降并且只会有一次穿过0.

用这个性质,我们我可在线段树中记录正数负数的个数和和,以及最大的负数以及答案.

修改操作:如果当前最大负数+d<=0,那么就直接加到懒惰标记中,否则就暴力向下传递.

因为每个节点最多被额外访问该区间负数个数次,所以所有点总共会被额外访问O(nlogn)次,在加上修改操作和询问操作的普通访问O(mlogn)次,所以时间复杂度是有保证的.

谢谢mhy12345的讲解.

 

  1 /**************************************************************
  2     Problem: 4127
  3     User: idy002
  4     Language: C++
  5     Result: Accepted
  6     Time:7872 ms
  7     Memory:49256 kb
  8 ****************************************************************/
  9  
 10 #include <cstdio>
 11 #include <vector>
 12 #include <algorithm>
 13 #define min(a,b) ((a)<(b)?(a):(b))
 14 #define max(a,b) ((a)>(b)?(a):(b))
 15 #define abs(a) ((a)<0?-(a):(a))
 16 #define oo 0x3f3f3f3f3f3f3f3fLL
 17 #define N 200010
 18 //#define fprintf(...)
 19 using namespace std;
 20  
 21 typedef long long dnt;
 22  
 23 void getn( int &v ) {
 24     char ch=getchar();
 25     bool neg = false;
 26     while( ch!='-' && (ch<'0' || ch>'9') ) ch=getchar();
 27     if( ch=='-' ) {
 28         neg = true;
 29         ch = getchar();
 30     }
 31     v = ch-'0';
 32     ch = getchar();
 33     while( '0'<=ch && ch<='9' ) {
 34         v = v*10+ch-'0';
 35         ch = getchar();
 36     }
 37     if( neg ) v=-v;
 38 }
 39  
 40 struct Node {
 41     dnt ans, sum[2], cnt[2], nmx, tag;
 42     Node *ls, *rs;
 43     inline void init( int v ) {
 44         if( v<0 ) {
 45             sum[0] = v;
 46             cnt[0] = 1;
 47             sum[1] = 0;
 48             cnt[1] = 0;
 49             ans = -v;
 50             tag = 0;
 51             nmx = v;
 52         } else {
 53             sum[0] = 0;
 54             cnt[0] = 0;
 55             sum[1] = v;
 56             cnt[1] = 1;
 57             tag = 0;
 58             ans = v;
 59             nmx = -oo;
 60         }
 61     }
 62     inline void update() {
 63         sum[0] = ls->sum[0] + rs->sum[0];
 64         sum[1] = ls->sum[1] + rs->sum[1];
 65         cnt[0] = ls->cnt[0] + rs->cnt[0];
 66         cnt[1] = ls->cnt[1] + rs->cnt[1];
 67         ans = ls->ans + rs->ans;
 68         nmx = max( ls->nmx, rs->nmx );
 69     }
 70     inline void pushdown() {
 71         if( tag ) {
 72             ls->nmx += tag;
 73             rs->nmx += tag;
 74             ls->sum[0] += ls->cnt[0]*tag;
 75             ls->sum[1] += ls->cnt[1]*tag;
 76             rs->sum[0] += rs->cnt[0]*tag;
 77             rs->sum[1] += rs->cnt[1]*tag;
 78             ls->ans = ls->sum[1]-ls->sum[0];
 79             rs->ans = rs->sum[1]-rs->sum[0];
 80             ls->tag += tag;
 81             rs->tag += tag;
 82             tag = 0;
 83         }
 84     }
 85     void modify( int lf, int rg, int L, int R, int delta ) {
 86         if( lf==rg ) {
 87             if( cnt[0] ) {
 88                 if( sum[0]+delta<=0 ) {
 89                     sum[0]+=delta;
 90                     nmx = sum[0];
 91                     ans = -sum[0];
 92                 } else {
 93                     sum[1] = sum[0]+delta;
 94                     ans = sum[1];
 95                     cnt[1] = 1;
 96                     sum[0] = cnt[0] = 0;
 97                     nmx = -oo;
 98                 }
 99             } else {
100                 sum[1]+=delta;
101                 ans = sum[1];
102             }
103             return;
104         }
105         if( L<=lf && rg<=R && nmx+delta<=0 ) {
106             nmx += delta;
107             sum[0] += cnt[0]*delta;
108             sum[1] += cnt[1]*delta;
109             ans = sum[1]-sum[0];
110             tag += delta;
111             return;
112         }
113         pushdown();
114         int mid=(lf+rg)>>1;
115         if( L<=mid ) ls->modify(lf,mid,L,R,delta);
116         if( R>mid ) rs->modify(mid+1,rg,L,R,delta);
117         update();
118     }
119     dnt query( int lf, int rg, int L, int R ) {
120         if( L<=lf && rg<=R ) return ans;
121         pushdown();
122         int mid=(lf+rg)>>1;
123         dnt rt = 0;
124         if( L<=mid ) rt+=ls->query(lf,mid,L,R);
125         if( R>mid ) rt+=rs->query(mid+1,rg,L,R);
126         update();
127         return rt;
128     }
129 }pool[N*3], *tail=pool, *root;
130  
131 int n, m;
132 int aa[N], bb[N];
133 int head[N], dest[N<<1], next[N<<1], etot;
134 int fat[N], siz[N], son[N], top[N], dep[N], vid[N], qu[N], bg, ed;
135  
136 void adde( int u, int v ) {
137     etot++;
138     dest[etot] = v;
139     next[etot] = head[u];
140     head[u] = etot;
141 }
142 Node *build( int lf, int rg ) {
143     Node *nd = ++tail;
144     if( lf==rg) {
145         nd->init(bb[lf]);
146         return nd;
147     }
148     int mid=(lf+rg)>>1;
149     nd->ls = build( lf, mid );
150     nd->rs = build( mid+1, rg );
151     nd->update();
152     return nd;
153 }
154 void build_dcp( int s ) {
155     //  fat dep
156     fat[s] = 0;
157     dep[s] = 1;
158     qu[bg=ed=1] = s;
159     while( bg<=ed ) {
160         int u=qu[bg++];
161         for( int t=head[u]; t; t=next[t] ) {
162             int v=dest[t];
163             if( v==fat[u] ) continue;
164             fat[v] = u;
165             dep[v] = dep[u]+1;
166             qu[++ed] = v;
167         }
168     }
169     //  siz son
170     for( int i=ed; i>=1; i-- ) {
171         int u=qu[i], p=fat[u];
172         siz[u]++;
173         if( p ) {
174             siz[p] += siz[u];
175             if( siz[son[p]]<siz[u] ) son[p]=u;
176         }
177     }
178     //  vid top
179     vid[s] = 1;
180     top[s] = s;
181     for( int i=1; i<=ed; i++ ) {
182         int u=qu[i];
183         int cur=vid[u]+1;
184         if( son[u] ) {
185             vid[son[u]] = cur;
186             top[son[u]] = top[u];
187             cur += siz[son[u]];
188         }
189         for( int t=head[u]; t; t=next[t] ) {
190             int v=dest[t];
191             if( v==fat[u] || v==son[u] ) continue;
192             vid[v] = cur;
193             top[v] = v;
194             cur += siz[v];
195         }
196     }
197     //  segment tree
198     for( int i=1; i<=n; i++ ) 
199         bb[vid[i]] = aa[i];
200 //  for( int i=1; i<=n; i++ )
201 //      fprintf( stderr, "%d ", bb[i] );
202 //  fprintf( stderr, "\n" );
203     root = build( 1, n );
204 }
205 void modify( int u, int v, int delta ) {
206     while( top[u]!=top[v] ) {
207         if( dep[top[u]]<dep[top[v]] ) swap(u,v);
208         root->modify(1,n,vid[top[u]],vid[u],delta);
209 //      fprintf( stderr, "modify( %d %d %d )\n", vid[top[u]], vid[u], delta );
210         u=fat[top[u]];
211     }
212     if( dep[u]<dep[v] ) swap(u,v);
213     root->modify(1,n,vid[v],vid[u],delta);
214 //  fprintf( stderr, "modify( %d %d %d )\n", vid[v], vid[u], delta );
215 }
216 dnt query( int u, int v ) {
217     dnt rt = 0;
218     while( top[u]!=top[v] ) {
219         if( dep[top[u]]<dep[top[v]] ) swap(u,v);
220         rt += root->query(1,n,vid[top[u]],vid[u]);
221 //      fprintf( stderr, "query( %d %d ) rt = %lld\n", vid[top[u]], vid[u], rt );
222         u=fat[top[u]];
223     }
224     if( dep[u]<dep[v] ) swap(u,v);
225     rt += root->query(1,n,vid[v],vid[u]);
226 //  fprintf( stderr, "query( %d %d ) rt = %lld\n", vid[v], vid[u], rt );
227     return rt;
228 }
229 int main() {
230     getn(n); getn(m);
231     for( int i=1; i<=n; i++ )
232         getn(aa[i]);
233     for( int i=1,u,v; i<n; i++ ) {
234         getn(u); getn(v);
235         adde( u, v );
236         adde( v, u );
237     }
238     build_dcp(1);
239     for( int t=1,opt,u,v,d; t<=m; t++ ) {
240         getn(opt);
241         if( opt==1 ) {
242             getn(u);getn(v);getn(d);
243             modify( u, v, d );
244         } else {
245             getn(u); getn(v);
246             printf( "%lld\n", query(u,v) );
247         }
248     }
249 }
View Code

 

posted @ 2015-06-07 14:57  idy002  阅读(496)  评论(0编辑  收藏  举报