题目链接
https://www.lydsy.com/JudgeOnline/problem.php?id=3052
思路
达成成就:卡BZOJ*1(逃)
这道题……大概就是一道树上莫队吧。
A点B点跳的方法很玄学,具体见代码。
代码
#include <cstdio>
#include <cmath>
#include <algorithm>
const int maxn=100000;
struct query
{
int l,r,t,id;
};
struct modify
{
int pos,prec,nowc;
};
query q[maxn+10];
modify d[maxn+10];
int n,m,qq,belong[maxn+10],val[maxn+10],cur[maxn+10],color[maxn+10],block_cnt,dfn_cnt;
int pre[maxn*2+10],now[maxn+10],son[maxn*2+10],tot,fa[maxn+10][20],size,cnt[maxn+10];
int nowl,nowr,nowt,deep[maxn+10],block_size[maxn+10],dfn[maxn+10],vis[maxn+10],numq,numc;
long long nowans,ans[maxn+10];
bool cmp(const query &a,const query &b)
{
if(belong[a.l]==belong[b.l])
{
if(belong[a.r]==belong[b.r])
{
return a.t<b.t;
}
return belong[a.r]<belong[b.r];
}
return belong[a.l]<belong[b.l];
}
inline int ins(int a,int b)
{
pre[++tot]=now[a];
now[a]=tot;
son[tot]=b;
return 0;
}
int dfs(int u)
{
if((!fa[u][0])||(block_size[belong[fa[u][0]]]>=size))
{
belong[u]=++block_cnt;
block_size[block_cnt]=1;
}
else
{
belong[u]=belong[fa[u][0]];
++block_size[belong[u]];
}
deep[u]=deep[fa[u][0]]+1;
dfn[u]=++dfn_cnt;
int j=now[u];
while(j)
{
int v=son[j];
if(v!=fa[u][0])
{
fa[v][0]=u;
dfs(v);
}
j=pre[j];
}
return 0;
}
int search()
{
size=(int)pow(n,2.0/3.0);
dfs(1);
for(register int j=1; j<=18; ++j)
{
for(register int i=1; i<=n; ++i)
{
fa[i][j]=fa[fa[i][j-1]][j-1];
}
}
return 0;
}
inline int lca(int a,int b)
{
if(deep[a]<deep[b])
{
std::swap(a,b);
}
for(register int i=18; i>=0; --i)
{
if(deep[fa[a][i]]>=deep[b])
{
a=fa[a][i];
}
}
if(a==b)
{
return a;
}
for(register int i=18; i>=0; --i)
{
if(fa[a][i]!=fa[b][i])
{
a=fa[a][i];
b=fa[b][i];
}
}
return fa[a][0];
}
int change(int a)
{
vis[a]^=1;
if(vis[a])
{
nowans+=1ll*cur[++cnt[color[a]]]*val[color[a]];
}
else
{
nowans-=1ll*cur[cnt[color[a]]--]*val[color[a]];
}
return 0;
}
inline int change(int pos,int col)
{
if(vis[pos])
{
nowans-=1ll*cur[cnt[color[pos]]--]*val[color[pos]];
nowans+=1ll*cur[++cnt[col]]*val[col];
}
color[pos]=col;
return 0;
}
inline int reverse(int a,int b)
{
while(a!=b)
{
if(deep[a]<deep[b])
{
std::swap(a,b);
}
change(a);
a=fa[a][0];
}
return 0;
}
inline int solve(int x)
{
while(nowt<q[x].t)
{
++nowt;
change(d[nowt].pos,d[nowt].nowc);
}
while(nowt>q[x].t)
{
change(d[nowt].pos,d[nowt].prec);
--nowt;
}
reverse(nowl,q[x].l);
reverse(nowr,q[x].r);
int f=lca(nowl=q[x].l,nowr=q[x].r);
change(f);
ans[q[x].id]=nowans;
change(f);
return 0;
}
int main()
{
scanf("%d%d%d",&n,&m,&qq);
for(register int i=1; i<=m; ++i)
{
scanf("%d",&val[i]);
}
for(register int i=1; i<=n; ++i)
{
scanf("%d",&cur[i]);
}
for(register int i=1; i<n; ++i)
{
int a,b;
scanf("%d%d",&a,&b);
ins(a,b);
ins(b,a);
}
for(register int i=1; i<=n; ++i)
{
scanf("%d",&color[i]);
}
search();
while(qq--)
{
int op,a,b;
scanf("%d%d%d",&op,&a,&b);
if(op)
{
if(dfn[a]>dfn[b])
{
std::swap(a,b);
}
q[++numq].l=a;
q[numq].r=b;
q[numq].t=numc;
q[numq].id=numq;
}
else
{
d[++numc].pos=a;
d[numc].prec=color[a];
d[numc].nowc=color[a]=b;
}
}
nowt=numc;
nowans=0;
std::sort(q+1,q+numq+1,cmp);
while(nowt<q[1].t)
{
++nowt;
change(d[nowt].pos,d[nowt].nowc);
}
while(nowt>q[1].t)
{
change(d[nowt].pos,d[nowt].prec);
--nowt;
}
reverse(q[1].l,q[1].r);
int gg=lca(q[1].l,q[1].r);
change(gg);
ans[q[1].id]=nowans;
change(gg);
nowl=q[1].l;
nowr=q[1].r;
for(register int i=2; i<=numq; ++i)
{
solve(i);
}
for(register int i=1; i<=numq; ++i)
{
#ifdef ONLINE_JUDGE
printf("%lld\n",ans[i]);
#else
printf("%I64d\n",ans[i]);
#endif
}
return 0;
}