BZOJ 3052: [wc2013]糖果公园【树上带修莫队

80 篇文章 0 订阅
2 篇文章 0 订阅

是这样的……

几天前

Flaze:我要学莫队QAQ我觉得整个机房只有我不会莫队QAQ

花花:那你去写糖果公园吧,写了就会了

Flaze【突然兴奋】:吼啊资瓷啊!

…………然后………………在颓了一万年后【才不是冒险卡关了】……就敲了那么一会儿23333


#include<bits/stdc++.h>
#define MAXN 200005
using namespace std ;	int n , m , Q ;
inline int read() {
	register int ch = getchar() ;
	while (!isdigit(ch))	ch = getchar() ;
	register int rtn = 0 ;
	while (isdigit(ch))	rtn = rtn*10 + ch - '0' , ch = getchar() ;
	return rtn ;
}
//===========================================================
//===== OTHER =====
int V[MAXN] , W[MAXN] ;
int col[MAXN] , ori[MAXN] ;
long long ans[MAXN] ;
int laekov , yjq[MAXN] ;

//===========================================================
//===== TREE =====
struct t1 {
	int to,nxt ;
}edge[MAXN<<1] ;	int cnt_edge ;
int fst[MAXN] ;
inline void addedge(int x,int y) {
	edge[++cnt_edge].to = y ;
	edge[cnt_edge].nxt = fst[x] ;
	fst[x] = cnt_edge ;

	edge[++cnt_edge].to = x ;
	edge[cnt_edge].nxt = fst[y] ;
	fst[y] = cnt_edge ;
}

int fth[MAXN] , top[MAXN] , siz[MAXN] , son[MAXN] ;
int dpt[MAXN] ;
int dfn[MAXN] , cnt_dfs ;
int bg[MAXN] , ed[MAXN] ;

void dfs1(int now) {
	siz[now] = 1 ;
	for (int tmp = fst[now] ; tmp ; tmp = edge[tmp].nxt) {
		int aim = edge[tmp].to ;
		if (aim==fth[now])	continue ;
		fth[aim] = now ;
		dpt[aim] = dpt[now] + 1 ;
		dfs1(aim) ;
		if (siz[aim] > siz[son[now]])	son[now] = aim ;
		siz[now] += siz[aim] ;
	}
}

void dfs2(int now , int tp) {
	top[now] = tp ;
	dfn[ bg[now] = ++cnt_dfs ] = now ;
	if (son[now])	dfs2(son[now],tp) ;
	for (int tmp = fst[now] ; tmp ; tmp = edge[tmp].nxt) {
		int aim = edge[tmp].to ;
		if (aim==fth[now] || aim==son[now])	continue;
		dfs2(aim,aim) ;
	}
	dfn[ ed[now] = ++cnt_dfs ] = now ;
}

inline int LCA(int x,int y) {
	while (top[x]^top[y]) {
		if(dpt[top[x]] < dpt[top[y]])	y = fth[top[y]] ;
		else	x = fth[top[x]] ;
	}
	return dpt[x] < dpt[y] ? x : y ;
}

//===========================================================
//===== ASK & MODIFY =====
struct ASK {
	int l,r,id,tag,a,b,pre ;
	ASK(){}
	ASK(int a,int b,int l,int r,int id,int tag,int pre):
		a(a) , b(b) , l(l) , r(r) , id(id) , tag(tag) , pre(pre) {}
	bool operator < (const ASK ano) const {
		if (yjq[l]==yjq[ano.l])
			return yjq[r]==yjq[ano.r] ? pre < ano.pre : yjq[r]<yjq[ano.r] ;
		else	return yjq[l] < yjq[ano.l] ;
	}
}ask[MAXN] ;	int cnt_ask ;
struct MODIFY {
	int pos , pre , aft ;
	MODIFY(){}
	MODIFY(int pos,int pre,int aft):
		pos(pos) , pre(pre) , aft(aft) {}
}modify[MAXN] ;	int cnt_modify ;

//===========================================================
//===== FUNCTION =====
inline void init(){
	int read_opt , u , v ;
	for (int i=1;i<=Q;++i) {
		read_opt = read() , u = read() , v = read() ;
		if (read_opt) {
			int TAG = 0 , L , R ;
			if (dpt[u] > dpt[v])	swap(u,v) ;
			if (bg[u]<bg[v] && ed[u]>bg[v])
				L = bg[u] , R = bg[v] ;
			else	TAG = 1 , L = min(ed[u],ed[v]) , R = max(bg[u],bg[v]) ;
			ask[++cnt_ask] = ASK(u,v,L,R,cnt_ask,TAG,cnt_modify) ;
		} else {
			modify[++cnt_modify] = MODIFY(u,col[u],v) ;
			col[u] = v ;
		}
	}

	int NN = n<<1 ;
	laekov = pow(NN,2.0/3)*2.0/3.0 ;
	for (int i=1;i<=NN;++i)	yjq[i] = (i-1)/laekov + 1 ;

	sort(ask+1,ask+cnt_ask+1) ;
	for (int i=1;i<=n;++i)	col[i] = ori[i] ;
}

long long NOW = 0 ;
int vis[MAXN] , cnt[MAXN] ;

inline void change(int x,int opt) {
	if(!~opt)	NOW -= 1ll * W[ cnt[x]-- ] * V[x] ;
	else	NOW += 1ll * W[ ++cnt[x] ] * V[x] ;
}

inline void MD() {
	int L = 1 , R = 1 , TIME = 0 ;
	vis[dfn[L]] ^= 1 ;
	change(col[dfn[L]], vis[dfn[L]] ? 1 : -1) ;

	for (int i=1;i<=cnt_ask;++i) {
		int TIM = ask[i].pre ;
		while (TIME < TIM) {
			++TIME ;
			if (vis[modify[TIME].pos])
				change(modify[TIME].pre,-1) , change(modify[TIME].aft,1) ;
			col[modify[TIME].pos] = modify[TIME].aft ;
		}
		while (TIME > TIM) {
			if (vis[modify[TIME].pos])
				change(modify[TIME].aft,-1) , change(modify[TIME].pre,1) ;
			col[modify[TIME].pos] = modify[TIME].pre ;
			--TIME ;
		}
		while (L < ask[i].l) {
			int now = dfn[L] ;
			vis[now] ^= 1 ;
			change(col[ now ] , vis[now] ? 1 : -1) ;
			++L ;
		}
		while (L > ask[i].l) {
			int now = dfn[--L] ;
			vis[now] ^= 1 ;
			change(col[ now ] , vis[now] ? 1 : -1) ;
		}
		while (R < ask[i].r) {
			int now = dfn[++R] ;
			vis[now] ^= 1 ;
			change(col[ now ] , vis[now] ? 1 : -1) ;
		}
		while (R > ask[i].r) {
			int now = dfn[R] ;
			vis[now] ^= 1 ;
			change(col[ now ] , vis[now] ? 1 : -1) ; 
			--R ;
		}

		if (ask[i].tag) {
			int lca = LCA(ask[i].a,ask[i].b) ;
			change(col[lca],1);
			ans[ ask[i].id ] = NOW ;
			change(col[lca],-1);
		} else ans[ ask[i].id ] = NOW ;
	}
}

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)	ori[i] = col[i] = read() ;

	dfs1(1) , dfs2(1,1) ;
	init() ;

	MD() ;

	for (int i=1;i<=cnt_ask;++i)	printf("%lld\n",ans[i]) ;
	return 0 ;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值