bzoj-3052 糖果公园

题意:

给出一颗n个结点的树,每个结点上有一种糖果∈[1,m];

一个人经过这个结点品尝糖果j获得的愉悦度为w[time[j]]*val[j]  (其中time[j]指j的品尝次数);

给出q次操作,操作有两种:

1:更改某结点的糖果种类;

2:查询某两个结点路径上的愉悦度总和;

题解:

250s的神题,orz各位神犇;

将树分块,每块n^2/3大小,分成n^1/3块;

用莫队算法统计路径上每种糖果的数量;

但是这里有了修改,不能用原来的方式排序了;

所以以左端点所在块为第一关键字,右端点所在块为第二关键字,时间序为第三关键字为所有询问排序;

注意是对询问排序,而修改仍按时间序存储;

然后一一处理询问,每次更改端点之前先把时间调至某次修改之后;

每次调整都是O(1)的,答案就是每个糖果的val乘上w的前缀和了;

这样时间复杂度最坏在O(n^5/3)  (LCA的log似乎被忽视了);

我的代码可以跑进100s真是荣幸啊233

代码:

#include<math.h>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 110000
using namespace std;
typedef long long ll;
struct node
{
	int l,r,tim,posl,posr,no;
}Q[N];
int to[N<<1],next[N<<1],head[N];
int st[N],belong[N],deep[N],fa[N][20];
int a[N],s[N];
int opx[N],opf[N],opt[N],last[N];
int cnt,tot,bk,top;
ll v[N],w[N],ans[N];
ll now;
bool vis[N];
bool cmp(node a,node b)
{
	if(a.posl==b.posl)
	{
		if(a.posr==b.posr)
			return a.tim<b.tim;
		return a.posr<b.posr;
	}
	return a.posl<b.posl;
}
void add(int x,int y)
{
	to[++cnt]=y;
	next[cnt]=head[x];
	head[x]=cnt;
}
void dfs(int x,int pre,int d)
{
	deep[x]=d;
	fa[x][0]=pre;
	int i,y,b=top;
	for(i=head[x];i;i=next[i])
	{
		if((y=to[i])!=pre)
		{
			dfs(y,x,d+1);
			if(top-b>=bk)
			{
				tot++;
				while(top>b)
					belong[st[top--]]=tot;
			}
		}
	}
	st[++top]=x;
}
int Lca(int x,int y)
{
	while(deep[x]!=deep[y])
	{
		if(deep[x]<deep[y])
			swap(x,y);
		int k=log2(deep[x]-deep[y]);
		x=fa[x][k];
	}
	if(x==y)	return x;
	int k=log2(deep[x])+1;
	while(k>=0)
	{
		if(fa[x][k]!=fa[y][k])
			x=fa[x][k],y=fa[y][k];
		k--;
	}
	return fa[x][0];
}
void update(int x,int op)
{
	now-=w[s[x]]*v[x];
	s[x]+=op;
	now+=w[s[x]]*v[x];
}
void change(int t)
{
	if(a[opx[t]]==opf[t])
	{
		a[opx[t]]=opt[t];
		if(vis[opx[t]])
		{
			update(opf[t],-1);
			update(opt[t],1);
		}
	}
	else
	{
		a[opx[t]]=opf[t];
		if(vis[opx[t]])
		{
			update(opt[t],-1);
			update(opf[t],1);
		}
	}
}
void slove(int x1,int x2)
{
	int g=Lca(x1,x2);
	while(x1!=g)
	{
		update(a[x1],vis[x1]?-1:1);
		vis[x1]=!vis[x1];
		x1=fa[x1][0];
	}
	while(x2!=g)
	{
		update(a[x2],vis[x2]?-1:1);
		vis[x2]=!vis[x2];
		x2=fa[x2][0];
	}
}
int main()
{
	int n,m,q,i,j,k,l,r,x,y,len,op,temp,ti;
	scanf("%d%d%d",&n,&m,&q);
	bk=pow(n,2.0/3);
	for(i=1;i<=m;i++)
		scanf("%lld",v+i);
	for(i=1;i<=n;i++)
		scanf("%lld",w+i),w[i]=w[i-1]+w[i];
	for(i=1;i<n;i++)
	{
		scanf("%d%d",&x,&y);
		add(x,y),add(y,x);
	}
	for(i=1;i<=n;i++)
		scanf("%d",a+i),last[i]=a[i];
	dfs(1,0,0);
	while(top)
		belong[st[top--]]=tot;
	for(k=1;(1<<k)<=n;k++)
		for(i=1;i<=n;i++)
			fa[i][k]=fa[fa[i][k-1]][k-1];
	for(i=1,temp=len=0;i<=q;i++)
	{
		scanf("%d%d%d",&op,&x,&y);
		if(op)
		{
			temp++;
			if(belong[x]>belong[y])
				swap(x,y);
			Q[temp].l=x,Q[temp].r=y;
			Q[temp].posl=belong[x];
			Q[temp].posr=belong[y];
			Q[temp].tim=len,Q[temp].no=temp;
		}
		else
		{
			len++;
			opx[len]=x,opf[len]=last[x],opt[len]=y;
			last[x]=y;
		}
	}
	q=temp;
	sort(Q+1,Q+q+1,cmp);
	l=1,r=1,now=0,ti=0;
	for(i=1;i<=q;i++)
	{
		while(ti<Q[i].tim)	change(++ti);
		while(ti>Q[i].tim)	change(ti--);
		slove(l,Q[i].l);
		slove(r,Q[i].r);
		l=Q[i].l,r=Q[i].r;
		x=Lca(l,r);
		update(a[x],1);
		ans[Q[i].no]=now;
		update(a[x],-1);
	}
	for(i=1;i<=q;i++)
		printf("%lld\n",ans[i]);
	return 0;
}
时间: 2024-10-26 01:52:30

bzoj-3052 糖果公园的相关文章

bzoj 3052: [wc2013]糖果公园(带修改的树上莫队)

3052: [wc2013]糖果公园 Time Limit: 200 Sec  Memory Limit: 512 MB Submit: 892  Solved: 425 [Submit][Status][Discuss] Description Input Output Sample Input Sample Input Sample Output 84 131 27 84 HINT Source [Submit][Status][Discuss] 题解:bzoj 2120 和 bzoj 37

[bzoj 3052][wc2013]糖果公园

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3052 [wc2013]糖果公园 Time Limit: 200 Sec  Memory Limit: 512 MBSubmit: 1213  Solved: 609[Submit][Status][Discuss] Description Input Output Sample Input Sample Input Sample Output 84 131 27 84 树上莫队,把树分块,

bzoj 3052: [wc2013]糖果公园 带修改莫队

3052: [wc2013]糖果公园 Time Limit: 250 Sec  Memory Limit: 512 MBSubmit: 506  Solved: 189[Submit][Status] Description Input Output Sample Input Sample Input Sample Output 84 131 27 84 HINT 本来这道题想到了莫队算法,但是看到带修改就直接放弃了.结果看题解才发现带修改居然也能用莫队!!!之所以可以这样用,是因为修改的时间复

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

题目链接:BZOJ - 3052 题目分析 这道题就是非常经典的树上莫队了,并且是带修改的莫队. 带修改的莫队:将询问按照 左端点所在的块编号为第一关键字,右端点所在的块为第二关键字,位于第几次修改之后为第三关键字 排序. 我们将块的大小设置在 n^(2/3) ,这样一共有 n^(1/3) 个块.最后算法的总复杂度会是 n^(5/3) . 每一次如何从上一个询问转移来呢? 假设上一个询问是 (lx, ly, lt) ,这次的询问是 (x, y, t) .t 代表是在第 t 次修改操作之后. 首先

【BZOJ】3052: [wc2013]糖果公园 树分块+待修改莫队算法

[题目]#58. [WC2013]糖果公园 [题意]给定n个点的树,m种糖果,每个点有糖果ci.给定n个数wi和m个数vi,第i颗糖果第j次品尝的价值是v(i)*w(j).q次询问一条链上每个点价值的和或修改一个点的糖果ci.n,m,q<=10^5. [算法]树分块+带修改莫队算法 [题解]参考:WC 2013 糖果公园 park 题解 by vfleaking 首先树分块,参考王室联邦的方法.确定块大小为B,一遍DFS可以分成若干大小为[B,3B]的块,性质是块内两点距离至多为B. 定义(x,

【BZOJ-3052】糖果公园 树上带修莫队算法

3052: [wc2013]糖果公园 Time Limit: 200 Sec  Memory Limit: 512 MBSubmit: 883  Solved: 419[Submit][Status][Discuss] Description Input Output Sample Input Sample Output 84 131 27 84 HINT Source Solution 树上带修莫队 本质还是树上莫队,详情可以转 BZOJ-3757苹果树 但是这里需要修改,就需要一些特殊的地方

WC2013 糖果公园

COGS 1817. [WC2013]糖果公园 http://www.cogs.pro/cogs/problem/problem.php?pid=1817 ★★★☆   输入文件:park.in   输出文件:park.out   简单对比时间限制:8 s   内存限制:512 MB [题目描述] Candyland 有一座糖果公园,公园里不仅有美丽的风景.好玩的游乐项目,还有许多免费糖果的发放点,这引来了许多贪吃的小朋友来糖果公园玩. 糖果公园的结构十分奇特,它由 n 个游览点构成,每个游览点

[BZOJ3052][UOJ#58][WC2013]糖果公园

试题描述 Candyland 有一座糖果公园,公园里不仅有美丽的风景.好玩的游乐项目,还有许多免费糖果的发放点,这引来了许多贪吃的小朋友来糖果公园玩. 糖果公园的结构十分奇特,它由 n 个游览点构成,每个游览点都有一个糖果发放处,我们可以依次将游览点编号为 1 至 n.有 n?1 条双向道路连接着这些游览点,并且整个糖果公园都是连通的,即从任何一个游览点出发都可以通过这些道路到达公园里的所有其它游览点. 糖果公园所发放的糖果种类非常丰富,总共 m 种,它们的编号依次为 1 至 m.每一个糖果发放

[WC2013][UOJ58]糖果公园 莫队算法

这道题有毒!!!!!!!!!!!!!!!!!! 先贴个题面吧QwQ #58. [WC2013]糖果公园 Candyland 有一座糖果公园,公园里不仅有美丽的风景.好玩的游乐项目,还有许多免费糖果的发放点,这引来了许多贪吃的小朋友来糖果公园玩. 糖果公园的结构十分奇特,它由 nn 个游览点构成,每个游览点都有一个糖果发放处,我们可以依次将游览点编号为 11 至 nn.有 n?1n?1 条双向道路连接着这些游览点,并且整个糖果公园都是连通的,即从任何一个游览点出发都可以通过这些道路到达公园里的所有

AC日记——[WC2013]糖果公园 cogs 1817

[WC2013]糖果公园 思路: 带修改树上莫队(模板): 来,上代码: #include <cmath> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define maxn 100005 #define ll long long struct QueryType { ll u,v,t,id;