【BZOJ3052】【UOJ#58】【WC2013】糖果公园(树上莫队)

【BZOJ3052】【UOJ#58】【WC2013】糖果公园(树上莫队)

题面

UOJ
洛谷

Candyland 有一座糖果公园,公园里不仅有美丽的风景、好玩的游乐项目,还有许多免费糖果的发放点,这引来了许多贪吃的小朋友来糖果公园游玩。
糖果公园的结构十分奇特,它由 n 个游览点构成,每个游览点都有一个糖果发放处,我们可以依次将游览点编号为 1 至 n。有 n – 1 条 双向道路 连接着这些游览点,并且整个糖果公园都是 连通的 ,即从任何一个游览点出发都可以通过这些道路到达公园里的所有其它游览点。
糖果公园所发放的糖果种类非常丰富,总共有 m 种,它们的编号依次为 1至 m。每一个糖果发放处都只发放某种特定的糖果,我们用 C i 来表示 i 号游览点的糖果。
来到公园里游玩的游客都 不喜欢走回头路 ,他们总是从某个特定的游览点出发前往另一个特定的游览点,并游览途中的景点,这条路线一定是唯一的。他们经过每个游览点,都可以品尝到一颗对应种类的糖果。
大家对不同类型糖果的喜爱程度都不尽相同。根据游客们的反馈打分,我们得到了糖果的美味指数,第 i 种糖果的美味指数为 V i 。另外,如果一位游客反复地品尝同一种类的糖果,他肯定会觉得有一些腻。根据量化统计,我们得到了游客第 i 次品尝某类糖果的新奇指数 W i 。如果一位游客第 i 次品尝第 j 种糖果,那么他的愉悦指数 H 将会增加对应的美味指数与新奇指数的乘积,即 V j 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 的操作输出一行,用一个正整数
表示答案。

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

84
131
27
84

题解

终于学会树上莫队了。。
我是真的弱啊。。。

前置技能就是普通的莫队,还有[王室联邦]那道题目的树分块的方法。

然后其实和普通的莫队差别并不大。

推荐参考学长(ljh2000)的博客

我就是照着他的打的。
学长好强啊。。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define ll long long
#define RG register
#define MAX 111111
inline int read()
{
    RG int x=0,t=1;RG char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=-1,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return x*t;
}
struct Line{int v,next;}e[MAX<<1];
int h[MAX],cnt=1;
inline void Add(int u,int v){e[cnt]=(Line){v,h[u]};h[u]=cnt++;}
int n,m,Q,blk;
int dfn[MAX],dep[MAX],tim;
int f[20][MAX],S[MAX],top;
int gr,G[MAX],V[MAX],W[MAX],C[MAX],col[MAX];
int num[MAX];
bool vis[MAX];
ll ans,Ans[MAX];
int dfs(int u,int ff)
{
	int size=0;dfn[u]=++tim;
	dep[u]=dep[ff]+1;f[0][u]=ff;
	for(int i=h[u];i;i=e[i].next)
	{
		int v=e[i].v;if(v==ff)continue;
		size+=dfs(v,u);
		if(size>=blk){++gr;while(size--)G[S[top--]]=gr;size=0;}
	}
	S[++top]=u;
	return size+1;
}
int LCA(int u,int v)
{
	if(dep[u]<dep[v])swap(u,v);
	for(int i=19;~i;--i)if(dep[f[i][u]]>=dep[v])u=f[i][u];
	if(u==v)return u;
	for(int i=19;~i;--i)if(f[i][u]!=f[i][v])u=f[i][u],v=f[i][v];
	return f[0][u];
}
int cnt1,cnt2;
struct modify{int lc,nc,x;}b[MAX];
struct Query{int id,u,v,lm,lb,rb;}q[MAX];
bool operator<(Query a,Query b)
{
	if(a.lb!=b.lb)return a.lb<b.lb;
	if(a.rb!=b.rb)return a.rb<b.rb;
	return a.lm<b.lm;
}
void Change(int x)
{
	if(vis[x])
		ans-=1ll*V[C[x]]*W[num[C[x]]],--num[C[x]];
	else
		++num[C[x]],ans+=1ll*V[C[x]]*W[num[C[x]]];
	vis[x]^=1;
}
void ModifyColor(int x,int color)
{
	if(!vis[x])C[x]=color;
	else Change(x),C[x]=color,Change(x);
}
void ModifyLink(int u,int v)
{
	while(u!=v)
	{
		if(dep[u]<dep[v])Change(v),v=f[0][v];
		else Change(u),u=f[0][u];
	}
}
int main()
{
	n=read();m=read();Q=read();blk=pow(n,0.66);
	for(int i=1;i<=m;++i)V[i]=read();
	for(int i=1;i<=n;++i)W[i]=read();
	for(int i=1,u,v;i<n;++i)u=read(),v=read(),Add(u,v),Add(v,u);
	for(int i=1;i<=n;++i)C[i]=col[i]=read();
	dfs(1,0);
	for(int j=1;j<20;++j)
		for(int i=1;i<=n;++i)
			f[j][i]=f[j-1][f[j-1][i]];
	for(int i=1;i<=Q;++i)
	{
		int opt=read(),u=read(),v=read();
		if(!opt)b[++cnt2]=(modify){col[u],v,u},col[u]=v;
		else
		{
			if(dfn[u]>dfn[v])swap(u,v);++cnt1;
			q[cnt1]=(Query){cnt1,u,v,cnt2,G[u],G[v]};
		}
	}
	sort(&q[1],&q[cnt1+1]);
	int Pos=0,lca=LCA(q[1].u,q[1].v);;
	while(Pos<q[1].lm)++Pos,ModifyColor(b[Pos].x,b[Pos].nc);
	ModifyLink(q[1].u,q[1].v);Change(lca);
	Ans[q[1].id]=ans;Change(lca);
	for(int i=2;i<=cnt1;++i)
	{
		while(Pos<q[i].lm)++Pos,ModifyColor(b[Pos].x,b[Pos].nc);
		while(Pos>q[i].lm)ModifyColor(b[Pos].x,b[Pos].lc),--Pos;
		ModifyLink(q[i-1].u,q[i].u);ModifyLink(q[i-1].v,q[i].v);
		lca=LCA(q[i].u,q[i].v);
		Change(lca);Ans[q[i].id]=ans;Change(lca);
	}
	for(int i=1;i<=cnt1;++i)printf("%lld
",Ans[i]);
	return 0;
}

原文地址:https://www.cnblogs.com/cjyyb/p/8722763.html