[WC2013]糖果公园

Posted by Dispwnl on December 13, 2018

题目

题目描述

Candyland 有一座糖果公园,公园里不仅有美丽的风景、好玩的游乐项目,还有许多免费糖果的发放点,这引来了许多贪吃的小朋友来糖果公园游玩。

糖果公园的结构十分奇特,它由 $n$ 个游览点构成,每个游览点都有一个糖果发放处,我们可以依次将游览点编号为 $1$ 至 $n$。有 $n – 1$ 条双向道路连接着这些游览点,并且整个糖果公园都是连通的,即从任何一个游览点出发都可以通过这些道路到达公园里的所有其它游览点。

糖果公园所发放的糖果种类非常丰富,总共有 $m$ 种,它们的编号依次为 $1$ 至 $m$。每一个糖果发放处都只发放某种特定的糖果,我们用 $C_i$ 来表示 $i$ 号游览点的糖果。

来到公园里游玩的游客都不喜欢走回头路,他们总是从某个特定的游览点出发前往另一个特定的游览点,并游览途中的景点,这条路线一定是唯一的。他们经过每个游览点,都可以品尝到一颗对应种类的糖果。

大家对不同类型糖果的喜爱程度都不尽相同。 根据游客们的反馈打分,我们得到了糖果的美味指数, 第 $i$ 种糖果的美味指数为 $V_i$ 。另外,如果一位游客反复地品尝同一种类的糖果,他肯定会觉得有一些腻。根据量化统计,我们得到了游客第 $i$次品尝某类糖果的新奇指数 $W_i$ 。如果一位游客第 $i$ 次品尝第 $j$ 种糖果,那么他的愉悦指数 $H$ 将会增加对应的美味指数与新奇指数的乘积,即 $V_j\times W_i$ 。这位游客游览公园的愉悦指数最终将是这些乘积的和。

当然,公园中每个糖果发放点所发放的糖果种类不一定是一成不变的。有时,一些糖果点所发放的糖果种类可能会更改(也只会是 $m$ 种中的一种),这样的目的是能够让游客们总是感受到惊喜。

糖果公园的工作人员小 A 接到了一个任务,那就是根据公园最近的数据统计出每位游客游玩公园的愉悦指数。但数学不好的小 A 一看到密密麻麻的数字就觉得头晕,作为小 A 最好的朋友,你决定帮他一把。

输入输出格式

输入格式:

从文件 park.in 中读入数据。

第一行包含三个正整数 $n, m, q$, 分别表示游览点个数、 糖果种类数和操作次数。

第二行包含 $m$ 个正整数 $V_1 , V_2 , …, V_m$ 。

第三行包含 $n$ 个正整数 $W_1 , W_2 , …, W_n$ 。

第四行到第 $n + 2$ 行,每行包含两个正整数 $A_i , B_i$ ,表示这两个游览点之间有路径可以直接到达。

第 $n + 3$ 行包含 $n$ 个正整数 $C_1 , C_2 , …, C_n$ 。

接下来 $q$ 行, 每行包含三个整数 $Type, x, y$,表示一次操作:

若 $Type$ 为 $0$,则 $1 ≤ x ≤ n$, $1 ≤ y ≤ m$,表示将编号为 $x$ 的游览点发放的糖果类型改为 $y$;

若 $Type$ 为 $1$,则 $1 ≤ x, y ≤ n$,表示对出发点为 $x$,终止点为 $y$ 的路线询问愉悦指数。

输出格式:

输出到文件 park.out 中。

按照输入的先后顺序,对于每个 $Type$ 为 $1$ 的操作输出一行,用一个正整数表示答案。

输入输出样例

输入样例#1:

4 3 5
1 9 2
7 6 5 1
2 3
3 1
3 4
1 2 3 2
1 1 2
1 4 2
0 2 1
1 1 2
1 4 2

输出样例#1:

84
131
27
84

说明

【样例解释】

我们分别用

代表 $C_i$ 为 $1、 2、 3$ 的节点,在修改之前:

在将 $C_2$ 修改为 $1$ 之后:

【数据规模与约定】

对于所有的数据: $1 ≤ V_i , W_i ≤ 10^6,1 ≤ A_i , B_i ≤ n, 1 ≤ C_i ≤ m, W_1 , W_2 , …, W_n$ 是非递增序列,即对任意 $1 < i ≤ n$, 满足 $W_i ≤ W_{i-1}$ 。

其它的限制条件如下表所示:

题解

树上莫队的模板题

因为询问忘按块排序TLE了两发

代码

# include<iostream>
# include<cstring>
# include<cstdio>
# include<cmath>
# include<algorithm>
# define LL long long
using namespace std;
const int MAX=2e5+5;
struct q{
	int x,y;
}c[MAX<<1];
struct o{
	int x,val;
}upt[MAX];
int n,m,Q,k,Num,tot,cnt,tot1,tot2;
LL Ans;
int a[MAX],h[MAX],fa[MAX],NUM[MAX],num[MAX],d[MAX],top[MAX],son[MAX],siz[MAX],re[MAX],In[MAX],Out[MAX],w[MAX],v[MAX],pos[MAX];
LL ans[MAX];
struct p{
	int l,r,id,lca,pre;
	bool operator< (const p &a)
	const{
		if(pos[l]!=pos[a.l]) return pos[l]<pos[a.l];
		if(pos[r]!=pos[a.r]) return pos[r]<pos[a.r];
		return pre<a.pre;
	}
}qu[MAX];
int read()
{
	int x(0);
	char ch=getchar();
	for(;!isdigit(ch);ch=getchar());
	for(;isdigit(ch);x=x*10+ch-48,ch=getchar());
	return x;
}
void add()
{
	int x=read(),y=read();
	c[++Num]=(q){h[x],y},h[x]=Num;
	c[++Num]=(q){h[y],x},h[y]=Num;
}
void dfs(int x=1,int f=0)
{
	fa[x]=f,d[x]=d[f]+(siz[x]=1),re[In[x]=++tot]=x;
	for(int i=h[x];i;i=c[i].x)
	  if(c[i].y^f)
	  {
	  	dfs(c[i].y,x),siz[x]+=siz[c[i].y];
	  	if(siz[son[x]]<siz[c[i].y]) son[x]=c[i].y;
	  }
	re[Out[x]=++tot]=x;
}
void dfs1(int x=1,int tp=1)
{
	top[x]=tp;
	if(!son[x]) return;
	dfs1(son[x],tp);
	for(int i=h[x];i;i=c[i].x)
	  if((c[i].y^fa[x])&&(c[i].y^son[x])) dfs1(c[i].y,c[i].y);
}
int LCA(int x,int y)
{
	while(top[x]^top[y])
	{
		if(d[top[x]]<d[top[y]]) swap(x,y);
		x=fa[top[x]];
	}
	if(d[x]>d[y]) swap(x,y);
	return x;
}
void add(int x)
{
	if(++num[a[re[x]]]>=0) Ans+=1ll*w[num[a[re[x]]]]*v[a[re[x]]];
}
void del(int x)
{
	if(--num[a[re[x]]]>=0) Ans-=1ll*w[num[a[re[x]]]+1]*v[a[re[x]]];
}
void GET_TIME(int x,int l,int r)
{
	if(NUM[upt[x].x]==1)
	{
		if(--num[a[upt[x].x]]>=0) Ans-=1ll*w[num[a[upt[x].x]]+1]*v[a[upt[x].x]];
		if(++num[upt[x].val]>=0) Ans+=1ll*w[num[upt[x].val]]*v[upt[x].val];
	}
	swap(upt[x].val,a[upt[x].x]);
}
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,add());
	dfs(),dfs1(),k=pow(1.0*tot,2.0/3.0);
    if(tot%k) ++k;
	for(int i=1;i<=n;++i)
	  a[i]=read();
	for(int i=1,op,l,r,l_l,l_r,r_l,r_r;i<=Q;++i)
	  {
	  	op=read(),l=read(),r=read();
	  	if(!op) upt[++tot1]=(o){l,r};
	  	else if(op==1)
	  	{
	  		l_l=In[l],l_r=Out[l],r_l=In[r],r_r=Out[r],qu[++tot2].pre=tot1,qu[tot2].id=tot2;
	  		if(l_r<=r_l) qu[tot2].l=l_r,qu[tot2].r=r_l;
	  		else if(r_r<=l_l) qu[tot2].l=r_r,qu[tot2].r=l_l;
	  		else if(l_r<=r_r) qu[tot2].l=l_r,qu[tot2].r=r_r;
	  		else if(r_r<=l_r) qu[tot2].l=r_r,qu[tot2].r=l_r;
	  		qu[tot2].lca=LCA(l,r);
	  		if(qu[tot2].lca==l||qu[tot2].lca==r) qu[tot2].lca=0;
		}
	  }
	for(int i=1;i<=tot;++i)
	  pos[i]=(i-1)/k+1;
	sort(qu+1,qu+1+tot2);
	for(int i=1,l=1,r=0,now=0;i<=tot2;++i)
	  {
	  	while(l<qu[i].l) if(--NUM[re[l]]==1) add(l++);
	  	else del(l++);
		while(l>qu[i].l) if(++NUM[re[--l]]==2) del(l);
		else add(l);
		while(r<qu[i].r) if(++NUM[re[++r]]==2) del(r);
		else add(r);
		while(r>qu[i].r) if(--NUM[re[r]]==1) add(r--);
		else del(r--);
		while(now<qu[i].pre) GET_TIME(++now,l,r);
		while(now>qu[i].pre) GET_TIME(now--,l,r);
	  	if(qu[i].lca&&num[a[qu[i].lca]]>=0) Ans+=1ll*w[num[a[qu[i].lca]]+1]*v[a[qu[i].lca]];
	  	ans[qu[i].id]=Ans;
	  	if(qu[i].lca&&num[a[qu[i].lca]]>=0) Ans-=1ll*w[num[a[qu[i].lca]]+1]*v[a[qu[i].lca]];
	  }
	for(int i=1;i<=tot2;++i)
	  printf("%lld\n",ans[i]);
	return 0;
}