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 }