【WC2013】糖果公园 (树上带修改莫队)

3人阅读 评论(0) 收藏 举报
分类:

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

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

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

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

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

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

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

输入格式

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

第二行包含 mm 个正整数 v1,v2,,vmv1,v2,…,vm

第三行包含 nn 个正整数 w1,w2,,wnw1,w2,…,wn

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

第 n+3n+3 行包含 nn 个正整数 c1,c2,,cnc1,c2,…,cn

接下来 qq 行,每行包含三个整数 t,x,yt,x,y,表示一次操作:

若 tt 为 00,则 1xn1≤x≤n1ym1≤y≤m,表示编号为 xx 的游览点发放的糖果类型改为 yy

若 tt 为 11,则 1x,yn1≤x,y≤n,表示对出发点为 xx,终止点为 yy 的路线询问愉悦指数。

输出格式

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

样例一

input

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

output

84
131
27
84

限制与约定

对于所有的数据,1vi,wi1061≤vi,wi≤1061ai,bin1≤ai,bi≤n1cim1≤ci≤mw1,w2,,wnw1,w2,…,wn 是非递增序列,即对任意 1<in1<i≤n,满足 wiwi1wi≤wi−1

测试点编号nnmmqq其它限制
120≤2020≤2020≤20
22000≤20002000≤20002000≤2000
310000≤1000010000≤1000010000≤10000
480000≤80000100≤10080000≤80000没有修改操作;给出的图构成一条链
590000≤90000100≤10090000≤90000
680000≤8000080000≤8000080000≤80000没有修改操作
790000≤9000090000≤9000090000≤90000
880000≤8000080000≤8000080000≤80000给出的图构成一条链
990000≤9000090000≤9000090000≤90000
10100000≤100000100000≤100000100000≤100000

祝大家一遍 AC,求不虐萌萌哒测评机!

时间限制8s8s

空间限制512MB512MB




解题思路:用来学习莫队,挺好懂,希望以后做题能用上~!!


#include <bits/stdc++.h>
using namespace std;
typedef long long int ll;
const int MAXN = 100010;
ll W[MAXN], V[MAXN];
int N, M, Q;
int C[MAXN];

struct edge
{
	int to;
	int next;
} e[MAXN << 1];
int edge_num, head[MAXN];
void insert_edge(int u, int v)
{
	e[edge_num].to = v;
	e[edge_num].next = head[u];
	head[u] = edge_num++;
}

int blocksize, blocknum;
int sta[MAXN];
int top;
int deep[MAXN];
int block[MAXN];
int fa[MAXN][25], bin[25]; //求公共祖先用
void dfs(int x)
{
	int bottom = top;
	for (int i = 1; i < 25; i++)
		if (deep[x] >= bin[i])
			fa[x][i] = fa[fa[x][i - 1]][i - 1];
		else
			break;
	for (int i = head[x]; ~i; i = e[i].next)
	{
		int to = e[i].to;
		if (to != fa[x][0])
		{
			fa[to][0] = x;
			deep[to] = deep[x] + 1;
			dfs(to);
			if (top - bottom >= blocksize)
			{
				blocknum++;
				while (top != bottom)
					block[sta[top--]] = blocknum;
			}
		}
		sta[++top] = x;
	}
}

int LCA(int x, int y)
{
	if (deep[x] < deep[y])
		swap(x, y);
	int t = deep[x] - deep[y];
	for (int i = 0; bin[i] <= t; i++)
		if (t & bin[i])
			x = fa[x][i];
	for (int i = 24; i >= 0; i--)
		if (fa[x][i] != fa[y][i])
			x = fa[x][i], y = fa[y][i];
	if (x == y)
		return x;
	return fa[x][0];
}

struct Query
{
	int l;
	int r;
	int cti;
	int id;
} q[MAXN];
int qn;
bool cmp(Query a, Query b)
{
	if (block[a.l] != block[b.l])
		return block[a.l] < block[b.l];
	if (block[a.r] != block[b.r])
		return block[a.r] < block[b.r];
	return a.cti < b.cti;
}
struct Change
{
	int x;
	int val;
} cha[MAXN];
int cn;

ll res = 0;
ll ans[MAXN];

int num[MAXN], now;
bool vis[MAXN];//记录当前是否访问过

void Work(int x)//单点修改,重新暴力计算答案
{
	if (vis[x])//如果访问了,那就变成没访问
	{
		res -= V[C[x]] * W[num[C[x]]];
		num[C[x]]--;
		vis[x] = 0;
	}
	else
	{
		num[C[x]]++;
		res += V[C[x]] * W[num[C[x]]];
		vis[x] = 1;
	}
}

void Move(int x, int y)//暴力移动,不断地往最近公共祖先靠
{
	while (x != y)
	{
		if (deep[x] > deep[y])
			swap(x, y);
		Work(y);
		y = fa[y][0];
	}
}

void Change(int x, int &val)//时间漫游时做修改
{
	if (vis[x])
	{
		Work(x);//先变成没修改
		swap(C[x],val);//交换,用于下次漫游
		Work(x);//再修改为当前值的答案
	}
	else//即使没被访问,也要修改,为了后面漫游一致性
		swap(C[x],val);
}

void Traval(int ti)//时间漫游,把修改过的改回去,没修改的暴力修改
{
	for (int i = now + 1; i <= ti; i++)
		Change(cha[i].x, cha[i].val);
	for (int i = now; i > ti; i--)
		Change(cha[i].x, cha[i].val);
	now = ti;
}

int main()
{
	bin[0] = 1;
	for (int i = 1; i < 25; i++)
		bin[i] = bin[i - 1] << 1;
	memset(head, -1, sizeof(head));
	edge_num = 0;

	scanf("%d%d%d", &N, &M, &Q);
	blocksize = pow(N, 2.0 / 3.0);
	int x, y;
	for (int i = 1; i <= M; i++)
		scanf("%lld", &V[i]);
	for (int i = 1; i <= N; i++)
		scanf("%lld", &W[i]);
	for (int i = 2; i <= N; i++)
	{
		scanf("%d%d", &x, &y);
		insert_edge(x, y);
		insert_edge(y, x);
	}
	dfs(1);
	blocksize++;
	while (top)
		block[sta[top--]] = blocksize;

	for (int i = 1; i <= N; i++)
		scanf("%d", &C[i]);

	int op;
	for (int i = 1; i <= Q; i++)
	{
		scanf("%d%d%d", &op, &x, &y);
		if (op)
		{
			if (block[x] > block[y])//小优化,使得块直接更加接近
				swap(x, y);
			q[qn].l = x;
			q[qn].r = y;
			q[qn].id = qn;
			q[qn].cti = cn;
			qn++;
		}
		else
		{
			cn++;
			cha[cn].x = x;
			cha[cn].val = y;
		}
	}

	sort(q, q + qn, cmp);

	int lca = LCA(q[0].l, q[0].r);
	Traval(q[0].cti);
	Move(q[0].l, q[0].r);
	Work(lca);
	ans[q[0].id] = res;
	Work(lca);
	for (int i = 1; i < qn; i++)
	{
		Traval(q[i].cti);
		Move(q[i - 1].l, q[i].l);
		Move(q[i - 1].r, q[i].r);
		lca = LCA(q[i].l, q[i].r);//lca要单独计算,画画图就知道了
		Work(lca);
		ans[q[i].id] = res;
		Work(lca);
	}
	for (int i = 0; i < qn; i++)
		printf("%lld\n", ans[i]);

	return 0;
}







查看评论

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

是这样的…… 几天前 Flaze:我要学莫队QAQ我觉得整个机房只有我不会莫队QAQ 花花:那你去写糖果公园吧,写了就会了 Flaze【突然兴奋】:吼啊资瓷啊! …………然后………………在颓了一万年后...
  • Flaze_
  • Flaze_
  • 2017-01-26 19:26:58
  • 391

[bzoj3052][WC2013]糖果公园

题目大意给定一颗n个结点的树。每个结点有一种颜色。颜色种类为m。 一条路径的价值定义为 ∑i=1mw[cnt[i]]∗v[i]\sum_{i=1}^mw[cnt[i]]*v[i] 其中cnt[i...
  • WerKeyTom_FTD
  • WerKeyTom_FTD
  • 2016-05-09 20:08:23
  • 1570

BZOJ 3052 WC2013 糖果公园 带修改树上莫队

题目大意:给定一棵树,每个点有一个颜色,提供两种操作: 1.询问两点间路径上的Σv[a[i]]*w[k],其中a[i]代表这个点的颜色,k表示这个点是这种颜色第k次出现 2.修改某个点的颜色 V...
  • PoPoQQQ
  • PoPoQQQ
  • 2014-11-27 13:02:58
  • 3111

【BZOJ】【P3052】【wc2013】【糖果公园】【题解】【树上莫队】

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3052 学长好强啊!!感觉学长的代码比vfk的代码可读性好多了 http://hzwer.c...
  • u012732945
  • u012732945
  • 2014-12-24 17:08:38
  • 1561

【BZOJ 3052】 [wc2013]糖果公园

带修改的树上莫队~
  • Regina8023
  • Regina8023
  • 2015-01-28 20:39:12
  • 1249

树上(带修改)莫队算法-- bzoj4129 && bzoj3757

bzoj3757似乎因为版权挂了 首先,我们要熟悉序列莫队 然后考虑树上莫队 我们用(l,r)表示当前l到r这条链上的答案(不包括lca),现在考虑从(l,r)转移到(L,R)我们用(l,r)表...
  • lcrtest
  • lcrtest
  • 2016-07-10 12:52:15
  • 701

BZOJ 3052 [wc2013]糖果公园 树上莫队

BZOJ 3052 [wc2013]糖果公园 树上莫队
  • wzq_QwQ
  • wzq_QwQ
  • 2015-08-06 16:46:05
  • 1626

UOJ 58 BZOJ 3052 [wc2013] 糖果公园

树上带修莫队
  • SenyeLicone
  • SenyeLicone
  • 2017-04-28 21:36:47
  • 327

3052: [wc2013]糖果公园

3052: [wc2013]糖果公园 Time Limit: 200 Sec  Memory Limit: 512 MB Submit: 962  Solved: 464 [Submit][St...
  • CRZbulabula
  • CRZbulabula
  • 2016-08-11 19:05:43
  • 316

学习笔记——带修莫队

简介 普通的莫队算法相信大家都熟悉,那么如果有些问题加上修改操作是否可以用莫队维护呢?下面就介绍一种O(n53)O(n53)O(n^{\frac 5 3})的带修莫队算法。 算法详解 只需要...
  • Charlie_jilei
  • Charlie_jilei
  • 2018-02-25 12:13:21
  • 73
    个人资料
    持之以恒
    等级:
    访问量: 3万+
    积分: 2729
    排名: 1万+
    Visitors
    Flag Counter
    文章分类
    最新评论