大家都很强, 可与之共勉 。
4034: [HAOI2015]树上操作
Time Limit: 10 Sec Memory Limit: 256 MB
Description
有一棵点数为 N 的树,以点 1 为根,且树点有边权。然后有 M 个
操作,分为三种:
操作 1 :把某个节点 x 的点权增加 a 。
操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。
操作 3 :询问某个节点 x 到根的路径中所有点的点权和。
Input
第一行包含两个整数 N, M 。表示点数和操作数。接下来一行 N 个整数,表示树中节点的初始权值。接下来 N-1
行每行三个正整数 fr, to , 表示该树中存在一条边 (fr, to) 。再接下来 M 行,每行分别表示一次操作。其中
第一个数表示该操作的种类( 1-3 ) ,之后接这个操作的参数( x 或者 x a ) 。
Output
对于每个询问操作,输出该询问的答案。答案之间用换行隔开。
Sample Input
5 5
1 2 3 4 5
1 2
1 4
2 3
2 5
3 3
1 2 1
3 5
2 1 2
3 3
Sample Output
6
9
13
HINT
对于 100% 的数据, N,M<=100000 ,且所有输入数据的绝对值都不会超过 10^6 。
题解 1 : Dfs 序列做法
线段树维护一个长度为2 * n的序列,设2 * n 的序列为c 若当前节点为 u, 则 c [in [u]] = a [u], c [out [u]] = -a[u], 这样从1到in [u] 的c中序列和就是u 到 root的点权和 。
修改时in[u] + delta, out [u] 处 - delta 。
在Build线段树的时候打tag ( 若是in就为1, 反之-1), 维护区间tag 。
然后就是裸裸的线段树区间修改区间查询了 : )
/**************************************************************
Problem: 4034
User: Lazer2001
Language: C++
Result: Accepted
Time:3228 ms
Memory:20128 kb
****************************************************************/
# include <bits/stdc++.h>
const int N = 100005 ;
typedef long long LL ;
int n, m ;
int a [N], aa [N << 1] ;
int ev [N << 1] ;
int idx, in [N], out [N] ;
std :: vector < int > g [N] ;
struct node {
bool flag ;
int tag ; // for in [], out [] ;
LL sum, lazy ;
node *ls, *rs ;
inline void update ( ) {
sum = ls -> sum + rs -> sum ;
}
inline void pushdown ( int lf, int rg ) {
if ( flag ) {
ls -> flag = rs -> flag = flag ;
ls -> lazy += lazy ;
rs -> lazy += lazy ;
int mid = ( lf >> 1 ) + ( rg >> 1 ) + ( lf & rg & 1 ) ;
ls -> sum += 1LL * ls -> tag * lazy ;
rs -> sum += 1LL * rs -> tag * lazy ;
lazy = 0 ;
flag = false ;
}
}
} pool [N << 2], *tail = pool , *root ;
inline void Dfs ( int u, int f ) {
aa [in [u] = ++ idx] = a [u] ; ev [idx] = 1 ;
for ( int i = 0 ; i < ( int ) g [u].size ( ) ; ++ i )
if ( g [u] [i] ^ f )
Dfs ( g [u] [i], u ) ;
aa [out [u] = ++ idx] = -a [u] ; ev [idx] = -1 ;
}
node* Build ( int lf, int rg ) {
node* nd = ++ tail ;
if ( lf == rg ) {
nd -> sum = aa [lf] ;
nd -> tag = ev [lf] ;
nd -> lazy = 0 ;
nd -> flag = 0 ;
return nd ;
}
int mid = ( lf >> 1 ) + ( rg >> 1 ) + ( lf & rg & 1 ) ;
nd -> ls = Build ( lf, mid ) ;
nd -> rs = Build ( mid + 1, rg ) ;
nd -> tag = nd -> ls -> tag + nd -> rs -> tag ;
nd -> update ( ) ;
return nd ;
}
void Modify ( node* &nd, int lf, int rg, int L, int R, int delta ) {
if ( L <= lf && rg <= R ) {
nd -> lazy += delta ;
nd -> flag = true ;
nd -> sum += 1LL * nd -> tag * delta ;
return ;
}
nd -> pushdown ( lf, rg ) ;
int mid = ( lf >> 1 ) + ( rg >> 1 ) + ( lf & rg & 1 ) ;
if ( L <= mid ) Modify ( nd -> ls, lf, mid, L, R, delta ) ;
if ( R > mid ) Modify ( nd -> rs, mid + 1, rg, L, R, delta ) ;
nd -> update ( ) ;
}
LL Query ( node* &nd, int lf, int rg, int L, int R ) {
if ( L <= lf && rg <= R ) {
return nd -> sum ;
}
LL rt = 0 ;
nd -> pushdown ( lf, rg ) ;
int mid = ( lf >> 1 ) + ( rg >> 1 ) + ( lf & rg & 1 ) ;
if ( L <= mid ) rt += Query ( nd -> ls, lf, mid, L, R ) ;
if ( R > mid ) rt += Query ( nd -> rs, mid + 1, rg, L, R ) ;
return rt ;
// nd -> update ( ) ;
}
int main ( ) {
scanf ( "%d%d", & n, & m ) ;
for ( int i = 1 ; i <= n ; ++ i ) scanf ( "%d", a + i ) ;
for ( int i = 1 ; i < n ; ++ i ) {
static int u, v ;
scanf ( "%d%d", & u, & v ) ;
g [v].push_back ( u ) ;
g [u].push_back ( v ) ;
}
Dfs ( 1, 0 ) ;
root = Build ( 1, idx ) ;
while ( m -- ) {
static int opt, x, v ;
scanf ( "%d", & opt ) ;
switch ( opt ) {
case 1 : scanf ( "%d%d", & x, & v ) ; Modify ( root, 1, idx, in [x], in [x], v ) ; Modify ( root, 1, idx, out [x], out [x], v ) ; break ;
case 2 : scanf ( "%d%d", & x, & v ) ; Modify ( root, 1, idx, in [x], out [x], v ) ; break ;
case 3 : scanf ( "%d", & x ) ; printf ( "%lld\n", Query ( root, 1, idx, 1, in [x] ) ) ; break ;
}
}
}
————————————————————————————————
题解 2 : 树链剖分做法
待填……
Update : 17.11.3
NOIP之前来填这个啦,至少写熟悉了链剖。
/**************************************************************
Problem: 4034
User: Lazer2001
Language: C++
Result: Accepted
Time:1532 ms
Memory:20376 kb
****************************************************************/
# include <bits/stdc++.h>
inline int read ( ) {
# define SIZE 2000005
static std :: streambuf *fb ( std :: cin.rdbuf ( ) ) ;
static char buf [SIZE], *ss ( 0 ), *tt ( 0 ) ;
# define pick( ) ( (ss == tt) ? ( tt = buf + fb -> sgetn ( ss = buf, SIZE ), ((ss == tt) ? -1 : *(ss ++)) ) :*(ss ++) )
register int x, c ;
bool opt ( 1 ) ;
while ( ! isdigit ( c = pick ( ) ) && ( c ^ -1 ) && ( c ^ 45 ) ) ;
if ( c == 45 ) c = pick ( ), opt = 0 ;
for ( x = -48 + c ; isdigit ( c = pick ( ) ) ; ( x *= 10 ) += c - 48 ) ;
return opt ? x : -x ;
# undef pick
}
# define N 100010
struct node {
long long sum ;
long long lazy ;
bool flag ;
node *ls, *rs ;
inline void update ( ) {
sum = ls -> sum + rs -> sum ;
}
inline void pushdown ( int l, int r ) {
if ( flag ) {
ls -> flag = rs -> flag = 1 ;
int mid = ( l + r ) >> 1 ;
ls -> sum += 1LL * ( mid - l + 1 ) * lazy ;
rs -> sum += 1LL * ( r - mid ) * lazy ;
ls -> lazy += lazy ;
rs -> lazy += lazy ;
flag = 0 ;
lazy = 0 ;
}
}
} pool [N << 2], *pt = pool, *root ;
struct edge {
int to ; edge* nxt ;
} ;
struct Graph {
edge g [N << 1], *head [N] ;
Graph ( ) { memset ( head, 0, sizeof head ) ; }
inline void add_edge ( int u, int v ) {
static edge* NewEdge ( g ) ;
*( ++ NewEdge ) = ( edge ) { v, head [u] } ; head [u] = NewEdge ;
}
inline void add_double_edge ( int u, int v ) {
add_edge ( u, v ), add_edge ( v, u ) ;
}
inline edge*& operator [] ( const int& u ) { return head [u] ; }
} G ;
int n ;
int a [N] ;
int top [N], dfn [N], out [N], siz [N], son [N], fa [N], dep [N], seq [N], idx ;
# undef N
inline void Dfs1 ( int u, int f ) {
siz [u] = 1 ;
fa [u] = f ;
for ( edge* it = G [u] ; it ; it = it -> nxt ) {
int& v = it -> to ;
if ( v ^ f ) {
dep [v] = dep [u] + 1 ;
Dfs1 ( v, u ) ;
siz [u] += siz [v] ;
if ( siz [u] == 0 || siz [son [u]] < siz [v] ) {
son [u] = v ;
}
}
}
}
inline void Dfs2 ( int u, int tp ) {
top [u] = tp, dfn [u] = ++ idx, seq [idx] = u ;
if ( son [u] ) Dfs2 ( son [u], tp ) ;
for ( edge* it = G [u] ; it ; it = it -> nxt ) {
int& v = it -> to ;
if ( ( v ^ fa [u] ) && ( v ^ son [u] ) ) {
Dfs2 ( v, v ) ;
}
}
out [u] = idx ;
}
inline node* build ( int lf, int rg ) {
node* nd = pt ++ ;
nd -> sum = 0, nd -> flag = 0, nd -> lazy = 0 ;
if ( lf == rg ) {
nd -> sum = a [seq [lf]] ;
return nd ;
}
int mid = ( lf + rg ) >> 1 ;
nd -> ls = build ( lf, mid ) ;
nd -> rs = build ( mid + 1, rg ) ;
nd -> update ( ) ;
return nd ;
}
inline void Modify ( node*& nd, int lf, int rg, int L, int R, int delta ) {
if ( L <= lf && rg <= R ) {
nd -> sum += 1LL * ( rg - lf + 1 ) * delta ;
nd -> flag = 1 ;
nd -> lazy += delta ;
return ;
}
nd -> pushdown ( lf, rg ) ;
int mid = ( lf + rg ) >> 1 ;
if ( L <= mid ) Modify ( nd -> ls, lf, mid, L, R, delta ) ;
if ( R > mid ) Modify ( nd -> rs, mid + 1, rg, L, R, delta ) ;
nd -> update ( ) ;
}
inline long long Query ( node*& nd, int lf, int rg, int L, int R ) {
if ( L <= lf && rg <= R ) {
return nd -> sum ;
}
nd -> pushdown ( lf, rg ) ;
int mid = ( lf + rg ) >> 1 ;
long long rt ( 0 ) ;
if ( L <= mid ) rt = Query ( nd -> ls, lf, mid, L, R ) ;
if ( R > mid ) rt += Query ( nd -> rs, mid + 1, rg, L, R ) ;
return rt ;
}
inline void Modify ( int u, int v, int val ) {
while ( top [u] ^ top [v] ) {
if ( dep [top [u]] < dep [top [v]] ) u ^= v ^= u ^= v ;
Modify ( root, 1, n, dfn [top [u]], dfn [u], val ) ;
u = fa [top [u]] ;
}
if ( dep [u] < dep [v] ) u ^= v ^= u ^= v ;
Modify ( root, 1, n, dfn [v], dfn [u], val ) ;
}
inline long long Query ( int u, int v ) {
long long rt ( 0 ) ;
while ( top [u] ^ top [v] ) {
if ( dep [top [u]] < dep [top [v]] ) u ^= v ^= u ^= v ;
rt += Query ( root, 1, n, dfn [top [u]], dfn [u] ) ;
u = fa [top [u]] ;
}
if ( dep [u] < dep [v] ) u ^= v ^= u ^= v ;
rt += Query ( root, 1, n, dfn [v], dfn [u] ) ;
return rt ;
}
int main ( ) {
std :: ios :: sync_with_stdio ( 0 ) ;
std :: cin.tie ( 0 ) ;
:: n = read ( ) ;
int m ( read ( ) ) ;
for ( int i = 1 ; i <= n ; ++ i ) a [i] = read ( ) ;
for ( int i = 1 ; i < n ; ++ i ) {
G.add_double_edge ( read ( ), read ( ) ) ;
}
Dfs1 ( 1, 0 ) ;
Dfs2 ( 1, 1 ) ;
root = build ( 1, n ) ;
while ( m -- ) {
int opt ( read ( ) ) ;
switch ( opt ) {
case 1 : {
int u ( read ( ) ), val ( read ( ) ) ;
Modify ( root, 1, n, dfn [u], dfn [u], val ) ;
break ;
}
case 2 : {
int x ( read ( ) ), val ( read ( ) ) ;
Modify ( root, 1, n, dfn [x], out [x], val ) ;
break ;
}
case 3 : {
int x ( read ( ) ) ;
printf ( "%lld\n", Query ( 1, x ) ) ;
break ;
}
}
}
}
题解 3 : 树状数组做法
/**************************************************************
Problem: 4034
User: Lazer2001
Language: C++
Result: Accepted
Time:696 ms
Memory:7364 kb
****************************************************************/
# include <bits/stdc++.h>
char buf [1 << 16], *s ( 0 ), *t ( 0 ) ;
inline char pick ( ) {
if ( s == t )
t = buf + fread ( s = buf, 1, 1 << 16, stdin ) ;
if ( s == t ) return -1 ;
return ( *s ++ ) ;
}
inline void readIn ( int& x ) {
register char ch ;
static short opt ;
opt = ( ch != 45 ) ;
while ( ! isdigit ( ch = pick ( ) ) && ( ch ^ -1 ) && ( ch ^ 45 ) ) ;
if ( ch == -1 ) return ;
if ( ch == 45 ) { opt = 0 ; ch = pick ( ) ; }
for ( x = -48 + ch ; isdigit ( ch = pick ( ) ) ; ( x *= 10 ) += ch - 48 ) ;
opt ? 1 : x = -x ;
}
const int N = 100005 ;
int a [N] ;
int idx, dep [N], fa [N], in [N], out [N] ;
struct edge {
int to, nxt ;
edge ( ) { }
edge ( int to, int nxt ) : to ( to ), nxt ( nxt ) { }
} g [N << 1] ;
int head [N], ecnt ;
inline void Add_edge ( int u, int v ) {
g [++ ecnt] = edge ( v, head [u] ) ; head [u] = ecnt ;
}
class BIT {
private :
int n ;
long long rt, c [100005] ;
public :
inline void Init ( int n ) {
this -> n = n ;
// memset ( c, 0, sizeof ( long long ) * ( n + 1 ) ) ;
}
inline void Modify ( int pos, long long delta ) {
while ( pos <= n ) c [pos] += delta, pos += ( pos & -pos ) ;
}
inline void Modify ( int l, int r, long long delta ) {
Modify ( l, delta ) ; Modify ( r + 1, -delta ) ;
}
inline long long Query ( int pos ) {
for ( rt = 0 ; pos ; pos -= ( pos & -pos ) ) rt += c [pos] ;
return rt ;
}
} T1, T2;
inline void Dfs ( int u, int f ) {
in [u] = ++ idx ;
for ( register int i = head [u] ; i ; i = g [i].nxt ) {
int v = g [i].to ;
if ( v ^ f ) {
dep [v] = dep [u] + 1 ;
Dfs ( v, u ) ;
}
}
out [u] = idx ;
}
int main ( ) {
int n, m ;
readIn ( n ) ; readIn ( m ) ;
T1.Init ( n ), T2.Init ( n ) ;
for ( register int i = 1 ; i <= n ; ++ i ) readIn ( a [i] ) ;
for ( register int i = 1 ; i < n ; ++ i ) {
int u, v ;
readIn ( u ) ; readIn ( v ) ;
Add_edge ( u, v ) ;
Add_edge ( v, u ) ;
}
dep [1] = 1 ;
Dfs ( 1, 0 ) ;
for ( register int i = 1 ; i <= n ; ++ i ) T1.Modify ( in [i], out [i], a [i] ) ;
while ( m -- ) {
int opt, x, a ;
readIn ( opt ) ;
switch ( opt ) {
case 1 : readIn ( x ) ; readIn ( a ) ; T1.Modify ( in [x], out [x], a ) ; break ;
case 2 : readIn ( x ) ; readIn ( a ) ; T1.Modify ( in [x], out [x], ( long long ) -( dep [x] - 1 ) * a ) ; T2.Modify ( in [x], out [x], a ) ; break ;
case 3 : readIn ( x ) ; printf ( "%lld\n", ( long long ) T1.Query ( in [x] ) + ( long long ) T2.Query ( in [x] ) * dep [x] ) ; break ;
}
}
}