Luogu4074[WC2013] 糖果公园

4 篇文章 0 订阅
2 篇文章 0 订阅

原题链接:https://www.luogu.org/problemnew/show/P4074

糖果公园

题目描述

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

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

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

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

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

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

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

输入输出格式
输入格式:

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

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

第二行包含 m m 个正整数V1,V2,,Vm​ 。

第三行包含 n n 个正整数 W1,W2,,Wn

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

n+3 n + 3 行包含 n n 个正整数 C1,C2,,Cn

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

Type T y p e 0 0 ,则 1xn 1ym 1 ≤ y ≤ m ,表示将编号为 x x 的游览点发放的糖果类型改为y

Type T y p e 1 1 ,则 1x,yn ,表示对出发点为 x x ,终止点为y 的路线询问愉悦指数。

输出格式:

输出到文件 park.out 中。

按照输入的先后顺序,对于每个 Type T y p e 1 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

说明
【样例解释】

我们分别用

代表Ci 123 1 、 2 、 3 的节点,在修改之前:

在将 C2 C 2 修改为 1 1 之后:

【数据规模与约定】

对于所有的数据: 1Vi,Wi1061Ai,Bin1CimW1,W2,,Wn 是非递增序列,即对任意 1<in 1 < i ≤ n , 满足 WiWi1 W i ≤ W i − 1

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

题解

单点的插入很容易,所以我们直接上树上带修改莫队。

板子板子都是板子。。。

代码
#include<bits/stdc++.h>
#define ll long long
#define A(x) 1ll*v[k[x]]*w[cot[k[x]]]
using namespace std;
const int M=1e5+5;
struct sd{int x,y,t;};
sd ask[M],ope[M];
int dad[M],siz[M],son[M],top[M],dfn[M],dep[M],sta[M],v[M],w[M],k[M],col[M],cot[M],bel[M],pre[M];
int tot,zhan,n,m,q,SZ,num,sum;
bool vis[M];
ll res,ans[M];
vector<int>mmp[M];
bool operator <(sd a,sd b)
{
    if(bel[a.x]!=bel[b.x])return bel[a.x]<bel[b.x];
    if(bel[a.y]!=bel[b.y])return bel[a.y]<bel[b.y];
    return a.t<b.t;
}
void in()
{
    int a,b;
    scanf("%d%d%d",&n,&m,&q);SZ=(int)pow(n,2.0/3);
    for(int i=1;i<=m;++i)scanf("%d",&v[i]);
    for(int i=1;i<=n;++i)scanf("%d",&w[i]);
    for(int i=1;i<n;++i)scanf("%d%d",&a,&b),mmp[a].push_back(b),mmp[b].push_back(a);
    for(int i=1;i<=n;++i)scanf("%d",&k[i]),col[i]=k[i];
}
int dfs(int v,int f,int d)
{
    dad[v]=f,siz[v]=1,dep[v]=d,dfn[v]=++tot;
    int bs=0,to,now=zhan,tmp;
    for(int i=mmp[v].size()-1;i>=0;--i)
    {
        to=mmp[v][i];if(to==f)continue;tmp=dfs(to,v,d+1);
        if(tmp>bs)bs=tmp,son[v]=to;siz[v]+=tmp;
        if(zhan-now>=SZ){++num;while(zhan!=now)bel[sta[zhan--]]=num;}
    }
    sta[++zhan]=v;
    return siz[v];
}
void dfs(int v,int t)
{
    top[v]=t;int to;
    if(son[v])dfs(son[v],t);
    for(int i=mmp[v].size()-1;i>=0;--i){to=mmp[v][i];if(to==dad[v]||to==son[v])continue;dfs(to,to);}
}
int lca(int x,int y)
{
    while(top[x]!=top[y]){if(dep[top[x]]<dep[top[y]])swap(x,y);x=dad[top[x]];}
    return dep[x]<dep[y]?x:y;
}
void rev(int x){if(!vis[x])++cot[k[x]],res+=A(x);else res-=A(x),--cot[k[x]];vis[x]^=1;}
void walk(int x,int y){while(x!=y){if(dep[x]<dep[y])swap(x,y);rev(x);x=dad[x];}}
void modi(int x,int y)
{
    if(!vis[x])k[x]=y;
    else res-=A(x),cot[k[x]]--,k[x]=y,cot[k[x]]++,res+=A(x);
}
void ac()
{
    memset(ans,-1,sizeof(ans));
    int a,b,c,X,Y,tim,lc;sd hh;
    dfs(1,0,1);dfs(1,1);
    if(zhan){num++;while(zhan)bel[sta[zhan--]]=num;}
    tot=zhan=0;
    for(int i=1;i<=q;++i)
    {
        scanf("%d%d%d",&a,&hh.x,&hh.y);hh.t=i;
        if(a){if(dfn[hh.x]>dfn[hh.y])swap(hh.x,hh.y);ask[++zhan]=hh;}
        else{pre[++tot]=col[hh.x];col[hh.x]=hh.y;ope[tot]=hh;}
    }
    ope[tot+1].t=q+1;X=Y=1;tim=0;
    sort(ask+1,ask+1+zhan);
    for(int i=1;i<=zhan;++i)
    {
        walk(X,ask[i].x);walk(Y,ask[i].y);X=ask[i].x,Y=ask[i].y;
        while(ope[tim+1].t<=ask[i].t)tim++,modi(ope[tim].x,ope[tim].y);
        while(ope[tim].t>ask[i].t)modi(ope[tim].x,pre[tim]),tim--;
        lc=lca(X,Y);rev(lc);ans[ask[i].t]=res;rev(lc);
    }
    for(int i=1;i<=q;++i)if(~ans[i])printf("%lld\n",ans[i]);
}
int main()
{
    in();ac();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ShadyPi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值