bzoj 4034

 

我写的是 DFS序+线段树

DFS序(出去的位置要单独建点)上,进入的位置是权值,出去的位置是权值的相反数,可以证明节点i到根节点的路径上的点的权值和是DFS序上1~in[i]的和。

只要搞出每个区间的进入位置和出去位置的和,就可以打标记了。

  1 /**************************************************************
  2     Problem: 4034
  3     User: idy002
  4     Language: C++
  5     Result: Accepted
  6     Time:2748 ms
  7     Memory:26616 kb
  8 ****************************************************************/
  9  
 10 #include <cstdio> 
 11 #include <cstdlib> 
 12 #define fprintf(...) 
 13 #define N 100010 
 14   
 15 typedef long long dnt; 
 16 struct Node { 
 17     dnt s, tag; 
 18     int tc[2]; 
 19     Node *ls, *rs; 
 20 }pool[N*6], *tail=pool, *root; 
 21   
 22 int n, m; 
 23 int head[N], dest[N+N], next[N+N], etot; 
 24 int in[N], out[N], type[N+N], ww[N], sww[N+N], idc; 
 25 bool vis[N]; 
 26   
 27 Node *build( int lf, int rg ) { 
 28     Node *nd = ++tail; 
 29     if( lf==rg ) { 
 30         nd->s = sww[lf]; 
 31         nd->tc[type[lf]]=1; 
 32         nd->tc[type[lf]^1]=0; 
 33         return nd; 
 34     } 
 35     int mid=(lf+rg)>>1; 
 36     nd->ls = build( lf, mid ); 
 37     nd->rs = build( mid+1, rg ); 
 38     nd->tc[0] = nd->ls->tc[0] + nd->rs->tc[0]; 
 39     nd->tc[1] = nd->ls->tc[1] + nd->rs->tc[1]; 
 40     nd->s = nd->ls->s + nd->rs->s; 
 41     fprintf( stderr, "[%d,%d] tc[0]=%d tc[1]=%d\n", lf, rg, nd->tc[0], nd->tc[1] ); 
 42     return nd; 
 43 } 
 44 inline void pushdown( Node *nd ) { 
 45     if( nd->tag ) { 
 46         nd->ls->s += nd->ls->tc[0]*nd->tag - nd->ls->tc[1]*nd->tag; 
 47         nd->rs->s += nd->rs->tc[0]*nd->tag - nd->rs->tc[1]*nd->tag; 
 48         nd->ls->tag += nd->tag; 
 49         nd->rs->tag += nd->tag; 
 50         nd->tag = 0; 
 51     } 
 52 } 
 53 inline void update( Node *nd ) { 
 54     nd->s = nd->ls->s + nd->rs->s; 
 55 } 
 56 void modify( Node *nd, int lf, int rg, int L, int R, dnt delta ) { 
 57     if( L<=lf && rg<=R ) { 
 58         nd->s += nd->tc[0]*delta - nd->tc[1]*delta; 
 59         nd->tag += delta; 
 60         return; 
 61     } 
 62     int mid=(lf+rg)>>1; 
 63     pushdown(nd); 
 64     if( L<=mid ) modify( nd->ls, lf, mid, L, R, delta ); 
 65     if( R>mid ) modify( nd->rs, mid+1, rg, L, R, delta ); 
 66     update( nd ); 
 67 } 
 68 dnt query( Node *nd, int lf, int rg, int L, int R ) { 
 69     if( L<=lf && rg<=R ) { 
 70         fprintf( stderr, "( %d %d ) = %lld\n", lf, rg, nd->s ); 
 71         return nd->s; 
 72     } 
 73     int mid=(lf+rg)>>1; 
 74     pushdown(nd); 
 75     dnt rt = 0; 
 76     if( L<=mid ) rt += query( nd->ls, lf, mid, L, R ); 
 77     if( R>mid ) rt += query( nd->rs, mid+1, rg, L, R ); 
 78     update(nd); 
 79     return rt; 
 80 } 
 81 void adde( int u, int v ) { 
 82     etot++; 
 83     next[etot] = head[u]; 
 84     dest[etot] = v; 
 85     head[u] = etot; 
 86 } 
 87 void dfs( int u, int fa ) { 
 88     if( vis[u] ) { 
 89         exit(0); 
 90         return; 
 91     } 
 92     vis[u] = true; 
 93     idc++; 
 94     in[u] = idc; 
 95     type[idc] = 0; 
 96     sww[idc] = ww[u]; 
 97     for( int t=head[u]; t; t=next[t] ) { 
 98         int v=dest[t]; 
 99         if( v==fa ) continue; 
100         dfs(v,u); 
101     } 
102     idc++; 
103     out[u] = idc; 
104     type[idc] = 1; 
105     sww[idc] = -ww[u]; 
106 } 
107 void mdf_sig( int u, int a ) { 
108     modify( root, 1, idc, in[u], in[u], +a ); 
109     modify( root, 1, idc, out[u], out[u], +a ); 
110     fprintf( stderr, "modify( %d %d %d )\n", in[u], in[u], +a ); 
111     fprintf( stderr, "modify( %d %d %d )\n", out[u], out[u], +a ); 
112 } 
113 void mdf_sub( int u, int a ) { 
114     modify( root, 1, idc, in[u], out[u], +a ); 
115     fprintf( stderr, "modify( %d %d %d )\n", in[u], out[u], +a ); 
116 } 
117 dnt query( int u ) { 
118     dnt rt = query( root, 1, idc, 1, in[u] ); 
119     fprintf( stderr, "query( %d %d ) = %lld\n", 1, in[u], rt ); 
120     return rt; 
121 } 
122 int main() { 
123     scanf( "%d%d", &n, &m ); 
124     for( int i=1; i<=n; i++ ) 
125         scanf( "%d", ww+i ); 
126     for( int i=1,u,v; i<n; i++ ) { 
127         scanf( "%d%d", &u, &v ); 
128         adde( u, v ); 
129         adde( v, u ); 
130     } 
131     fprintf( stderr, "dfs(...)\n" ); 
132     dfs(1,1); 
133     fprintf( stderr, "\n" ); 
134     fprintf( stderr, "build(...)\n" ); 
135     root = build( 1, idc ); 
136     for( int t=0; t<m; t++ ) { 
137         int opt, u, a; 
138         scanf( "%d", &opt ); 
139         fprintf( stderr, "%d\n", opt ); 
140         if( opt==1 ) { 
141             scanf( "%d%d", &u, &a ); 
142             mdf_sig( u, a ); 
143         } else if( opt==2 ) { 
144             scanf( "%d%d", &u, &a ); 
145             mdf_sub( u, a ); 
146         } else { 
147             scanf( "%d", &u ); 
148             printf( "%lld\n", query(u) ); 
149         } 
150     } 
151 } 
152 
View Code

 


还有一种做法:链剖

以前一直以为链剖只能用于链修改和链查询。。。。

其实,链剖是一种特殊的DFS序,它合理地安排了DFS的顺序(先重儿子,再轻儿子),让我们可以把任意一条路径映射为O(logn)条连续的线段,然后就可以做很多问题了。

其次是和子树相关的问题,我们一般是把DFS序弄出来,然后一个子树就是连续的一段,这样实现子树相关的操作。

我们把两个结合起来就可以做到:链修改与查询+子树修改与查询。

(好像还有一种链剖解决子树问题的方法,就是每个节点再记录所有轻边代表的子树的信息)。

 

  1 #include <cstdio> 
  2 #include <cstdlib> 
  3 #define fprintf(...) 
  4 #define N 100010 
  5  
  6 typedef long long dnt; 
  7 struct Node { 
  8     dnt s, tag; 
  9     int tc[2]; 
 10     Node *ls, *rs; 
 11 }pool[N*6], *tail=pool, *root; 
 12  
 13 int n, m; 
 14 int head[N], dest[N+N], next[N+N], etot; 
 15 int in[N], out[N], type[N+N], ww[N], sww[N+N], idc; 
 16 bool vis[N]; 
 17  
 18 Node *build( int lf, int rg ) { 
 19     Node *nd = ++tail; 
 20     if( lf==rg ) { 
 21         nd->s = sww[lf]; 
 22         nd->tc[type[lf]]=1; 
 23         nd->tc[type[lf]^1]=0; 
 24         return nd; 
 25     } 
 26     int mid=(lf+rg)>>1; 
 27     nd->ls = build( lf, mid ); 
 28     nd->rs = build( mid+1, rg ); 
 29     nd->tc[0] = nd->ls->tc[0] + nd->rs->tc[0]; 
 30     nd->tc[1] = nd->ls->tc[1] + nd->rs->tc[1]; 
 31     nd->s = nd->ls->s + nd->rs->s; 
 32     fprintf( stderr, "[%d,%d] tc[0]=%d tc[1]=%d\n", lf, rg, nd->tc[0], nd->tc[1] ); 
 33     return nd; 
 34 } 
 35 inline void pushdown( Node *nd ) { 
 36     if( nd->tag ) { 
 37         nd->ls->s += nd->ls->tc[0]*nd->tag - nd->ls->tc[1]*nd->tag; 
 38         nd->rs->s += nd->rs->tc[0]*nd->tag - nd->rs->tc[1]*nd->tag; 
 39         nd->ls->tag += nd->tag; 
 40         nd->rs->tag += nd->tag; 
 41         nd->tag = 0; 
 42     } 
 43 } 
 44 inline void update( Node *nd ) { 
 45     nd->s = nd->ls->s + nd->rs->s; 
 46 } 
 47 void modify( Node *nd, int lf, int rg, int L, int R, dnt delta ) { 
 48     if( L<=lf && rg<=R ) { 
 49         nd->s += nd->tc[0]*delta - nd->tc[1]*delta; 
 50         nd->tag += delta; 
 51         return; 
 52     } 
 53     int mid=(lf+rg)>>1; 
 54     pushdown(nd); 
 55     if( L<=mid ) modify( nd->ls, lf, mid, L, R, delta ); 
 56     if( R>mid ) modify( nd->rs, mid+1, rg, L, R, delta ); 
 57     update( nd ); 
 58 } 
 59 dnt query( Node *nd, int lf, int rg, int L, int R ) { 
 60     if( L<=lf && rg<=R ) { 
 61         fprintf( stderr, "( %d %d ) = %lld\n", lf, rg, nd->s ); 
 62         return nd->s; 
 63     } 
 64     int mid=(lf+rg)>>1; 
 65     pushdown(nd); 
 66     dnt rt = 0; 
 67     if( L<=mid ) rt += query( nd->ls, lf, mid, L, R ); 
 68     if( R>mid ) rt += query( nd->rs, mid+1, rg, L, R ); 
 69     update(nd); 
 70     return rt; 
 71 } 
 72 void adde( int u, int v ) { 
 73     etot++; 
 74     next[etot] = head[u]; 
 75     dest[etot] = v; 
 76     head[u] = etot; 
 77 } 
 78 void dfs( int u, int fa ) { 
 79     if( vis[u] ) { 
 80         exit(0); 
 81         return; 
 82     } 
 83     vis[u] = true; 
 84     idc++; 
 85     in[u] = idc; 
 86     type[idc] = 0; 
 87     sww[idc] = ww[u]; 
 88     for( int t=head[u]; t; t=next[t] ) { 
 89         int v=dest[t]; 
 90         if( v==fa ) continue; 
 91         dfs(v,u); 
 92     } 
 93     idc++; 
 94     out[u] = idc; 
 95     type[idc] = 1; 
 96     sww[idc] = -ww[u]; 
 97 } 
 98 void mdf_sig( int u, int a ) { 
 99     modify( root, 1, idc, in[u], in[u], +a ); 
100     modify( root, 1, idc, out[u], out[u], +a ); 
101     fprintf( stderr, "modify( %d %d %d )\n", in[u], in[u], +a ); 
102     fprintf( stderr, "modify( %d %d %d )\n", out[u], out[u], +a ); 
103 } 
104 void mdf_sub( int u, int a ) { 
105     modify( root, 1, idc, in[u], out[u], +a ); 
106     fprintf( stderr, "modify( %d %d %d )\n", in[u], out[u], +a ); 
107 } 
108 dnt query( int u ) { 
109     dnt rt = query( root, 1, idc, 1, in[u] ); 
110     fprintf( stderr, "query( %d %d ) = %lld\n", 1, in[u], rt ); 
111     return rt; 
112 } 
113 int main() { 
114     scanf( "%d%d", &n, &m ); 
115     for( int i=1; i<=n; i++ ) 
116         scanf( "%d", ww+i ); 
117     for( int i=1,u,v; i<n; i++ ) { 
118         scanf( "%d%d", &u, &v ); 
119         adde( u, v ); 
120         adde( v, u ); 
121     } 
122     fprintf( stderr, "dfs(...)\n" ); 
123     dfs(1,1); 
124     fprintf( stderr, "\n" ); 
125     fprintf( stderr, "build(...)\n" ); 
126     root = build( 1, idc ); 
127     for( int t=0; t<m; t++ ) { 
128         int opt, u, a; 
129         scanf( "%d", &opt ); 
130         fprintf( stderr, "%d\n", opt ); 
131         if( opt==1 ) { 
132             scanf( "%d%d", &u, &a ); 
133             mdf_sig( u, a ); 
134         } else if( opt==2 ) { 
135             scanf( "%d%d", &u, &a ); 
136             mdf_sub( u, a ); 
137         } else { 
138             scanf( "%d", &u ); 
139             printf( "%lld\n", query(u) ); 
140         } 
141     } 
142 } 
View Code

 

posted @ 2015-04-30 16:33  idy002  阅读(238)  评论(0编辑  收藏  举报