BZOJ3052: [wc2013]糖果公园

Description

Input

Output

Sample Input

Sample Input

Sample Output

84
131
27
84

HINT


Source

树上带修莫队
树上莫队?用类似于括号序列的东西搞到序列上
注意分类讨论x和y互为祖先的情况
带修莫队?维护3个东西,l,r,t(时间戳)
三关键字排序
第一关键字l,第二关键字r,这两个按块来排
第三关键字t,在同一块中递增
如果我们把块的size搞成n^(2/3)
复杂度就是n^(5/3)
#include <bits/stdc++.h>
using namespace std;

const int MAXN = 200010;

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

int f[MAXN], g[MAXN], id[MAXN], tim, n, m, Q, sz;
int head[MAXN], cnt, last[MAXN], dep[MAXN], fa[MAXN][19];
int v[MAXN], w[MAXN], block, bl[MAXN], cnt1, cnt2, col[MAXN], appear[MAXN];
bool vis[MAXN];
long long ans[MAXN], cur;

struct query
{
	int l, r, t, id;
	bool operator < ( const query &b ) const { return ( bl[ l ] < bl[ b.l ] ) || ( bl[ l ] == bl[ b.l ] && bl[ r ] < bl[ b.r ] ) || ( bl[ l ] == bl[ b.l ] && bl[ r ] == bl[ b.r ] && t < b.t ); }
}a[MAXN], b[MAXN];

struct edge { int to, nxt; }e[MAXN];

inline void add(int x, int y) { e[ ++cnt ] = { y, head[ x ] }; head[ x ] = cnt; }
inline void addedge(int x, int y) { add( x, y ); add( y, x ); }

inline void dfs(int x)
{
	id[ f[ x ] = ++tim ] = x;
	for( int i = head[ x ] ; i ; i = e[ i ].nxt )
		if( e[ i ].to ^ fa[ x ][ 0 ] )
			fa[ e[ i ].to ][ 0 ] = x, dep[ e[ i ].to ] = dep[ x ] + 1, dfs( e[ i ].to );
	id[ g[ x ] = ++tim ] = x;
}

inline void init()
{
	for( int j = 1 ; j <= 18 ; j++ )
		for( int i = 1 ; i <= n ; i++ )
			fa[ i ][ j ] = fa[ fa[ i ][ j - 1 ] ][ j - 1 ];
}

inline void pushup(int &x, int d)
{
	for( int i = 18 ; i >= 0 ; i-- )
		if( d >= ( 1 << i ) ) d -= 1 << i, x = fa[ x ][ i ];
}

inline int lca(int x, int y)
{
	if( dep[ x ] < dep[ y ] ) swap( x, y );
	if( dep[ x ] ^ dep[ y ] ) pushup( x, dep[ x ] - dep[ y ] );
	if( x == y ) return x;
	for( int i = 18 ; i >= 0 ; i-- )
		if( fa[ x ][ i ] ^ fa[ y ][ i ] ) x = fa[ x ][ i ], y = fa[ y ][ i ];
	return fa[ x ][ 0 ];
}

inline void add(int x)
{
	if( vis[ x ] ) cur -= 1ll * v[ col[ x ] ] * w[ appear[ col[ x ] ]-- ];
	else cur += 1ll * v[ col[ x ] ] * w[ ++appear[ col[ x ] ] ];
	vis[ x ] ^= 1;
}

inline void modify(int x, int c) { if( vis[ x ] ) { add( x ); col[ x ] = c; add( x ); } else col[ x ] = c; }

int main()
{
	n = read(); m = read(); Q = read();
	for( int i = 1 ; i <= m ; i++ ) v[ i ] = read();
	for( int i = 1 ; i <= n ; i++ ) w[ i ] = read();
	for( int i = 1 ; i < n ; i++ ) addedge( read(), read() );
	for( int i = 1 ; i <= n ; i++ ) last[ i ] = col[ i ] = read();
	dfs( 1 ); init(); sz = pow( tim, 2.0 / 3 );
	for( int i = 1 ; i <= tim ; i++ ) bl[ i ] = ( i - 1 ) / sz;
	while( Q-- )
	{
		int opt = read(), x = read(), y = read();
		if( opt )
		{
			if( f[ x ] > f[ y ] ) swap( x, y );
			a[ ++cnt1 ] = { lca( x, y ) == x ? f[ x ] : g[ x ], f[ y ], cnt2, cnt1 };
		}
		else b[ ++cnt2 ].l = x, b[ cnt2 ].r = last[ x ], last[ x ] = b[ cnt2 ].t = y;
	}
	sort( a + 1, a + cnt1 + 1 );
	int L = 1, R = 0, T = 1;
	for( int i = 1 ; i <= cnt1 ; i++ )
	{
		while( T <= a[ i ].t ) modify( b[ T ].l, b[ T ].t ), T++;
		while( T > a[ i ].t ) modify( b[ T ].l, b[ T ].r ), T--;
		while( L > a[ i ].l ) add( id[ --L ] );
		while( L < a[ i ].l ) add( id[ L++ ] );
		while( R > a[ i ].r ) add( id[ R-- ] );
		while( R < a[ i ].r ) add( id[ ++R ] );
		//printf( "%d %d %d %d\n", a[ i ].l, a[ i ].r, a[ i ].t, a[ i ].id );
		int x = id[ L ], y = id[ R ], LCA = lca( x, y );
		if( x != LCA && y != LCA ) { add( LCA ); ans[ a[ i ].id ] = cur; add( LCA ); }
		else ans[ a[ i ].id ] = cur;
	}
	for( int i = 1 ; i <= cnt1 ; i++ ) printf( "%lld\n", ans[ i ] );
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值