Description
在一片土地上有N个城市,通过N-1条无向边互相连接,形成一棵树的结构,相邻两个城市的距离为1,其中第i个城市的价值为value[i]。
不幸的是,这片土地常常发生地震,并且随着时代的发展,城市的价值也往往会发生变动。
接下来你需要在线处理M次操作:
0 x k 表示发生了一次地震,震中城市为x,影响范围为k,所有与x距离不超过k的城市都将受到影响,该次地震造成的经济损失为所有受影响城市的价值和。
1 x y 表示第x个城市的价值变成了y。
为了体现程序的在线性,操作中的x、y、k都需要异或你程序上一次的输出来解密,如果之前没有输出,则默认上一次的输出为0。
Input
第一行包含两个正整数N和M。
第二行包含N个正整数,第i个数表示value[i]。
接下来N-1行,每行包含两个正整数u、v,表示u和v之间有一条无向边。
接下来M行,每行包含三个数,表示M次操作。
Output
包含若干行,对于每个询问输出一行一个正整数表示答案。
Sample Input
8 1
1 10 100 1000 10000 100000 1000000 10000000
1 2
1 3
2 4
2 5
3 6
3 7
3 8
0 3 1
1 10 100 1000 10000 100000 1000000 10000000
1 2
1 3
2 4
2 5
3 6
3 7
3 8
0 3 1
Sample Output
11100101
HINT
1<=N,M<=100000
1<=u,v,x<=N
1<=value[i],y<=10000
0<=k<=N-1
Source
非常裸的动态点分治
对每个节点开两个线段树,记录它自己的和它子树到父亲的,容斥即可
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 100010;
const int MAXM = 6000020;
inline int read()
{
int sc = 0; char ch = getchar();
while( ch < '0' || ch > '9' ) ch = getchar();
while( ch >= '0' && ch <= '9' ) sc = sc * 10 + ch - '0', ch = getchar();
return sc;
}
struct edge
{
int to, nxt;
}e[MAXN << 1];
int n, fa[MAXN], size[MAXN],head[MAXN], cnt, val[MAXN];
int root[MAXN][2], tot, ls[MAXM], rs[MAXM], sum[MAXM];
int Q, lastans, a[MAXN << 1][20], table[MAXN << 1], dep[MAXN], pos[MAXN], tim;
bool vis[MAXN];
inline void add(int x, int y) { e[ ++cnt ].to = y; e[ cnt ].nxt = head[ x ]; head[ x ] = cnt; }
inline void addedge(int x, int y) { add( x, y ); add( y, x ); }
inline void modify(int &x, int l, int r, int p, int v)
{
// printf( "%d %d\n", p, v );
if( !x ) x = ++tot;
sum[ x ] += v;
if( l == r ) return ;
int mid = l + r >> 1;
if( p <= mid ) modify( ls[ x ], l, mid, p, v );
else modify( rs[ x ], mid + 1, r, p, v );
}
inline int query(int x, int l, int r, int ql, int qr)
{
// printf( "%d %d %d %d %d\n", l, r, ql, qr, sum[ x ] );
if( !x ) return 0;
if( l == ql && r == qr ) return sum[ x ];
int mid = l + r >> 1;
if( qr <= mid ) return query( ls[ x ], l, mid, ql, qr );
if( ql > mid ) return query( rs[ x ], mid + 1, r, ql, qr );
return query( ls[ x ], l, mid, ql, mid ) + query( rs[ x ], mid + 1, r, mid + 1, qr );
}
inline void findroot(int x, int fa, int Size, int &cg)
{
bool flag = true;
size[ x ] = 1;
for( int i = head[ x ] ; i ; i = e[ i ].nxt )
if( !vis[ e[ i ].to ] && e[ i ].to != fa )
{
findroot( e[ i ].to, x, Size, cg );
size[ x ] += size[ e[ i ].to ];
if( ( size[ e[ i ].to ] << 1 ) > Size ) flag = false;
}
if( ( Size - size[ x ] << 1 ) > Size ) flag = false;
if( flag ) cg = x;
}
inline void getsize(int x, int fa)
{
size[ x ] = 1;
for( int i = head[ x ] ; i ; i = e[ i ].nxt )
if( !vis[ e[ i ].to ] && e[ i ].to != fa )
getsize( e[ i ].to, x ), size[ x ] += size[ e[ i ].to ];
}
inline void dfs(int &rt, int x, int fa, int dep)
{
modify( rt, 0, n, dep, val[ x ] );
for( int i = head[ x ] ; i ; i = e[ i ].nxt )
if( !vis[ e[ i ].to ] && e[ i ].to != fa )
dfs( rt, e[ i ].to, x, dep + 1 );
}
inline int solve(int x, int Size)
{
int cg;
findroot( x, 0, Size, cg );
vis[ cg ] = 1;
getsize( cg, 0 );
// printf( "root[%d][0]\n", cg );
modify( root[ cg ][ 0 ], 0, n, 0, val[ cg ] );
for( int i = head[ cg ] ; i ; i = e[ i ].nxt )
if( !vis[ e[ i ].to ] )
{
// printf( "root[%d][0]\n", cg );
dfs( root[ cg ][ 0 ], e[ i ].to, 0, 1 );
int tmp;
findroot( e[ i ].to, 0, size[ e[ i ].to ], tmp );
fa[ tmp ] = cg;
// printf( "root[%d][1]\n", tmp );
dfs( root[ tmp ][ 1 ], e[ i ].to, 0, 1 );
solve( e[ i ].to, size[ e[ i ].to ] );
}
return cg;
}
inline void DFS(int x, int fa)
{
a[ pos[ x ] = ++tim ][ 0 ] = dep[ x ] = dep[ fa ] + 1;
for( int i = head[ x ] ; i ; i = e[ i ].nxt )
if( e[ i ].to ^ fa )
DFS( e[ i ].to, x ), a[ ++tim ][ 0 ] = dep[ x ];
}
inline int lca(int x, int y)
{
x = pos[ x ]; y = pos[ y ];
if( x > y ) swap( x, y );
int len = table[ y - x + 1 ];
return min( a[ x ][ len ], a[ y - ( 1 << len ) + 1 ][ len ] );
}
inline int dis(int x, int y) { return dep[ x ] + dep[ y ] - ( lca( x, y ) << 1 ); }
inline void update(int x, int y)
{
int c = y - val[ x ];
modify( root[ x ][ 0 ], 0, n, 0, c );
for( int i = x ; fa[ i ] ; i = fa[ i ] )
{
int d = dis( x, fa[ i ] );
modify( root[ fa[ i ] ][ 0 ], 0, n, d, c );
modify( root[ i ][ 1 ], 0, n, d, c );
}
val[ x ] = y;
}
inline int cal(int x, int y)
{
int ret = query( root[ x ][ 0 ], 0, n, 0, y );
for( int i = x ; fa[ i ] ; i = fa[ i ] )
{
int d = dis( x, fa[ i ] );
if( d > y ) continue;
ret += query( root[ fa[ i ] ][ 0 ], 0, n, 0, y - d );
// printf( "[%d]\n", ret );
ret -= query( root[ i ][ 1 ], 0, n, 0, y - d );
// printf( "[%d]\n", ret );
}
return ret;
}
int main()
{
// freopen( "a.in", "r", stdin );
// freopen( "a.out", "w", stdout );
n = read(); Q = read();
for( int i = 1 ; i <= n ; i++ ) val[ i ] = read();
for( int i = 1 ; i < n ; i++ ) addedge( read(), read() );
solve( 1, n );
DFS( 1, 0 );
// printf( "YJQ!root[3][1]=%d\n",root[ 3 ][ 1 ] );
for( int i = 2 ; i <= tim ; i++ ) table[ i ] = table[ i >> 1 ] + 1;
for( int j = 1 ; j <= table[ tim ] ; j++ )
for( int i = 1 ; i + ( 1 << j ) - 1 <= tim ; i++ )
a[ i ][ j ] = min( a[ i ][ j - 1 ], a[ i + ( 1 << j - 1 ) ][ j - 1 ] );
while( Q-- )
{
int opt = read(), x = read() ^ lastans, y = read() ^ lastans;
if( opt ) update( x, y );
else printf( "%d\n", lastans = cal( x, y ) );
}
}