UOJ 58 BZOJ 3052 [wc2013] 糖果公园

216 篇文章 0 订阅
6 篇文章 0 订阅

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

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

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

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

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

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

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

输入格式

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

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

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

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

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

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

若  t t 为  0 0,则  1xn 1≤x≤n 1ym 1≤y≤m,表示编号为  x x 的游览点发放的糖果类型改为  y y

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

输出格式

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

样例一

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,wi106 1≤vi,wi≤106 1ai,bin 1≤ai,bi≤n 1cim 1≤ci≤m w1,w2,,wn w1,w2,…,wn 是非递增序列,即对任意  1<in 1<i≤n,满足  wiwi1 wi≤wi−1

测试点编号 n n m m q q 其它限制
1 20 ≤20 20 ≤20 20 ≤20
2 2000 ≤2000 2000 ≤2000 2000 ≤2000
3 10000 ≤10000 10000 ≤10000 10000 ≤10000
4 80000 ≤80000 100 ≤100 80000 ≤80000 没有修改操作;给出的图构成一条链
5 90000 ≤90000 100 ≤100 90000 ≤90000
6 80000 ≤80000 80000 ≤80000 80000 ≤80000 没有修改操作
7 90000 ≤90000 90000 ≤90000 90000 ≤90000
8 80000 ≤80000 80000 ≤80000 80000 ≤80000 给出的图构成一条链
9 90000 ≤90000 90000 ≤90000 90000 ≤90000
10 100000 ≤100000 100000 ≤100000 100000 ≤100000

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

时间限制 8s 8s

空间限制 512MB 512MB

下载

样例数据下载

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

树上带修莫队~

和苹果树差不多,就是计数不太一样,而且因为有个修改,所以我们要给修改和询问加上一个时间标记。

按块把询问排序,第一关键字x的pos值,第二关键字y的pos值,第三关键字时间。(pos[x]<=pos[y])

然后需要考虑的就是时间递增的xy的递推,和无修改莫队一样;主要的是时间减小的递推比较麻烦。

这就相当于一个回溯的过程,所以我们在输入修改的时候就记录下修改前该位置的值,这样回溯就相当于把值改回去,与前面递推的部分是一样的。

pow(i,j)太神奇了,还能是小数的小数次方!

w[i],v[i],a[i],c[i],ans[i]以及记录目前答案的now都要开long long!

更新的时候忘了更新x和y导致WA了很久……以后写莫队的时候要注意呀!

(另这道题是卡评测利器啊2333)


#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
#define ll long long

int n,m,q,k,tot1,fi[100001],ne[200001],w[200001],fa[100001][18],dep[100001],pos[100001];
int stk[100001],cnt,top,tot,jin,nowtime,num[100001];
bool b[100001];
ll ans[100001],now,vv[100001],ww[1000001],a[100001],c[100001];

struct node{
	int x,y,id,time;
}que[100001];

struct node1{
	int x,y,last;
}ch[100001];

ll read()
{
	ll 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<<1)+(x<<3)+ch-'0';ch=getchar();}
	return x*f;
}

void add(int u,int v)
{
	w[++cnt]=v;ne[cnt]=fi[u];fi[u]=cnt;
	w[++cnt]=u;ne[cnt]=fi[v];fi[v]=cnt;
}

void dfs(int u)
{
	for(int i=1;(1<<i)<=dep[u];i++) fa[u][i]=fa[fa[u][i-1]][i-1];
	int now=top;
	for(int i=fi[u];i;i=ne[i])
	  if(w[i]!=fa[u][0])
	  {
	  	fa[w[i]][0]=u;dep[w[i]]=dep[u]+1;
	  	dfs(w[i]);
	  	if(top-now>=jin)
	  	{
	  		tot++;
	  		while(top>now) pos[stk[top--]]=tot;
	  	}
	  }
	stk[++top]=u;
}

int lca(int u,int v)
{
	if(dep[u]<dep[v]) swap(u,v);
	int now=dep[u]-dep[v];
	for(int i=0;i<=17;i++) if((1<<i)&now) u=fa[u][i];
	if(u==v) return u;
	for(int i=17;~i;i--) if(fa[u][i]!=fa[v][i]) u=fa[u][i],v=fa[v][i];
	return fa[u][0];
}

bool operator < (node u,node v)
{
	if(pos[u.x]==pos[v.x]) return pos[u.y]==pos[v.y] ? u.time<v.time:pos[u.y]<pos[v.y];
	return pos[u.x]<pos[v.x];
}

void xo(int u)
{
	if(b[u]) now-=vv[a[u]]*ww[num[a[u]]--];
	else now+=vv[a[u]]*ww[++num[a[u]]];
	b[u]^=1;
}

void chancol(int u,int v)
{
	if(b[u])
	{
		xo(u);a[u]=v;xo(u);
	}
	else a[u]=v;
}

void chan(int u,int v)
{
	while(u!=v) if(dep[u]>dep[v]) xo(u),u=fa[u][0];
	else xo(v),v=fa[v][0];
}

int main()
{
	n=read();m=read();q=read();
	for(int i=1;i<=m;i++) vv[i]=read();
	for(int i=1;i<=n;i++) ww[i]=read();
	for(int i=1;i<n;i++) add(read(),read());
	jin=pow(n,2.0/3)*0.5;dfs(1);
	while(top) pos[stk[top--]]=tot;
	for(int i=1;i<=n;i++) a[i]=c[i]=read();
	for(int i=1;i<=q;i++)
	{
		k=read();
		if(k)
		{
			que[++tot1].x=read(),que[tot1].y=read(),que[tot1].id=tot1,que[tot1].time=nowtime;
			if(pos[que[tot1].x]>pos[que[tot1].y]) swap(que[tot1].x,que[tot1].y);
		}
		else
		{
			ch[++nowtime].x=read(),ch[nowtime].y=read();
			ch[nowtime].last=c[ch[nowtime].x];c[ch[nowtime].x]=ch[nowtime].y;
		}
	}
	q=tot1;
	sort(que+1,que+q+1);
	int x=1,y=1,time=1;
	for(int i=1;i<=q;i++)
	{
		if(que[i].x!=x) chan(que[i].x,x),x=que[i].x;
		if(que[i].y!=y) chan(que[i].y,y),y=que[i].y;
		for(;time-1>que[i].time;time--) chancol(ch[time-1].x,ch[time-1].last);
		for(;time<=que[i].time && time<=nowtime;time++) chancol(ch[time].x,ch[time].y);
		k=lca(x,y);xo(k);
		ans[que[i].id]=now;xo(k);
	}
	for(int i=1;i<=q;i++) printf("%lld\n",ans[i]);
	return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值