BZOJ3730: 震波

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

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 ) );
	}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值