bzoj3052 [wc2013]糖果公园(树上莫队,带修改)

树上莫队参见spoj_cot2,带修改莫队参见bzoj2120.这道题就是把这俩和在一起了╭(╯^╰)╮。bzoj上时间很宽松。。大家如果没把握还是不要去爆oj了的好。给大家推荐个好地方UOJ,这题的题号是58。可以先在那过了再说。。uoj的评测机好好的说。。顺便我树上莫队也是从建了uoj的vfk那里学来的。。大家可以去搜一下他的博客。我在这里放链接是不是算侵权??不懂。。只能orz神犇。(因为打错变量调了一下午的我,欲哭无泪。辣鸡样例,打错变量都能过。。)

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#define ll long long
#define N 100005
using namespace std;
int n,m,qq,block,a[N],h[N],num=0,now=0,prev[N];
int fa[N][18],dep[N],stack[N],top=0,dfn_num=0,dfn[N];
int f[N],Log[N],tot=0,block_num=0,belong[N];
ll w[N],ans=0,ANS[N],v[N];
bool vis[N];
inline int read(){
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
	return x*f;
}
inline int swap(int &x,int &y){x^=y;y^=x;x^=y;}
struct edge{
	int to,next;
}data[N<<1];
struct timeflow{
	int pre,to,pos;
}modify[N];
struct query{
	int l,r,id,timen;
}q[N];
inline int cmp(query x,query y){
	if(belong[x.l]==belong[y.l]){
		return dfn[x.r]==dfn[y.r]?x.timen<y.timen:dfn[x.r]<dfn[y.r];
	}else return belong[x.l]<belong[y.l];
}
inline int dfs(int x){
	dfn[x]=++dfn_num;int size=0;
	for(int i=1;i<=Log[dep[x]];++i)
		fa[x][i]=fa[fa[x][i-1]][i-1];
	for(int i=h[x];i;i=data[i].next){
		int y=data[i].to;
		if(y==fa[x][0]) continue;
		fa[y][0]=x;dep[y]=dep[x]+1;
		size+=dfs(y);
		if(size>=block){
			++block_num;
			while(size--) belong[stack[top--]]=block_num;
		}
	}
	stack[++top]=x;
	return size+1;
}
inline void change(int x,int y){
	if(vis[x]){
		ans-=w[f[a[x]]]*v[a[x]];f[a[x]]--;
		a[x]=y;
		f[a[x]]++;ans+=w[f[a[x]]]*v[a[x]];
	}
	else a[x]=y;
}
inline int lca(int x,int y){
	if(dep[x]<dep[y]) swap(x,y);
	int d=dep[x]-dep[y];
	for(int i=0;i<=Log[d];++i)
		if(d&(1<<i)) x=fa[x][i];
	if(x==y) return x;
	for(int i=Log[n];i>=0;--i) 
		if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
	return fa[x][0];
}
inline void reverse(int x){
	if(vis[x]) ans-=w[f[a[x]]]*v[a[x]],f[a[x]]--;
	else f[a[x]]++,ans+=w[f[a[x]]]*v[a[x]];
	vis[x]^=1;
}
inline void solve(int x,int y){
	while(x!=y){
		if(dep[x]>dep[y]) reverse(x),x=fa[x][0];
		else reverse(y),y=fa[y][0];
	}
}
int main(){
//	freopen("a.in","r",stdin);
	n=read();m=read();qq=read();block=pow(n,2.0/3)*0.5;
	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){
		int x=read(),y=read();
		data[++num].to=y;data[num].next=h[x];h[x]=num;
		data[++num].to=x;data[num].next=h[y];h[y]=num;
	}
	for(int i=1;i<=n;++i) prev[i]=a[i]=read();
	Log[0]=-1;for(int i=1;i<=n;++i) Log[i]=Log[i>>1]+1;
	dep[1]=1;dfs(1);++block_num;
	while(top) belong[stack[top--]]=block_num;
	while(qq--){
		int op=read(),x=read(),y=read();
		if(!op){
			modify[++now].pre=prev[x];prev[x]=y;
			modify[now].to=y;modify[now].pos=x;
		}
		else{
			q[++tot].l=x;q[tot].r=y;q[tot].timen=now;q[tot].id=tot;
			if(belong[x]>belong[y]) swap(q[tot].l,q[tot].r);
		}
	}sort(q+1,q+tot+1,cmp);
	for(int i=1;i<=q[1].timen;++i) a[modify[i].pos]=modify[i].to;
	solve(q[1].l,q[1].r);int t=lca(q[1].l,q[1].r);
	ANS[q[1].id]=ans+v[a[t]]*(w[f[a[t]]+1]);
	for(int i=2;i<=tot;++i){
		for(int j=q[i-1].timen;j>q[i].timen;--j) change(modify[j].pos,modify[j].pre);
		for(int j=q[i-1].timen;j<q[i].timen;++j) change(modify[j+1].pos,modify[j+1].to);
		solve(q[i-1].l,q[i].l);solve(q[i-1].r,q[i].r);
		int t=lca(q[i].l,q[i].r);ANS[q[i].id]=ans+v[a[t]]*(w[f[a[t]]+1]);
	}
	for(int i=1;i<=tot;++i) printf("%lld\n",ANS[i]);
	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值