杭电2022 第1场 1007 Treasure(克鲁斯卡尔重构树+虚树)
\(n\)个点\(m\)条边的连通图,每个点有第\(c_i\)种权值为\(val_i\)的宝藏,问从\(x\)点出发只通过边权小于等于\(y\)的边可以获得的宝藏最大权值,每种宝藏权值只能算一遍。宝藏权值带修改。每种宝藏最多有10个。
建出克鲁斯卡尔重构树,考虑在节点上维护答案。发现每种宝藏最多有10个,所以可以建出每一种宝藏的虚树,在虚树上暴力修改。需要链上修改单点查询,树上差分之后成为单点修改,查询子树和。故使用树状数组维护克鲁斯卡尔重构树的\(dfs\)序即可。
(因为克鲁斯克鲁斯卡尔重构树的结构特殊,虚树代码有锅但是过了)
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
#define int long long
const int N=201000;
vector<int> vec[N];
int read(){
int sum=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){sum=sum*10+ch-'0';ch=getchar();}
return sum;
}
struct Edge{
int u,v,w;
}ed[N];
struct edge{
int to,nxt;
}e[N*2];
int tr[N*2],dfn[N*2];
int a[N],c[N],val[N],stack[N],top,tot,n,m,root,W[N*2],Size[N*2],deep[N*2],f[N*2][21];
int cnt,head[N*2],id[N*20],mx[N*20],Map[N*20],fa[N*20];
int find(int x){
if(fa[x]==x)return x;
else return fa[x]=find(fa[x]);
}
void add_edge(int u,int v){
cnt++;
e[cnt].nxt=head[u];
e[cnt].to=v;
head[u]=cnt;
}
void get_dfn(int u){
dfn[u]=++tot;
Size[u]=1;
for(int i=1;i<=20;i++)f[u][i]=f[f[u][i-1]][i-1];
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to;
deep[v]=deep[u]+1;
get_dfn(v);
Size[u]+=Size[v];
}
}
bool cmp_1(Edge a,Edge b){
return a.w<b.w;
}
bool cmp_2(int a,int b){
return dfn[a]<dfn[b];
}
int lowbit(int x){
return x&-x;
}
void add(int x,int w){
for(int i=x;i<=Size[root];i+=lowbit(i))tr[i]+=w;
}
int get_sum(int x){
int ans=0;
for(int i=x;i;i-=lowbit(i))ans+=tr[i];
return ans;
}
void change(int x,int w,int last){
mx[x]=w;
int now=x;
while(now){
if(id[now]==root){
add(dfn[id[now]],w-last);
break;
}
add(dfn[id[now]],w-last);
add(dfn[id[fa[now]]],last-w);
if(mx[fa[now]]<w)last=mx[fa[now]],mx[fa[now]]=w,now=fa[now];
else break;
}
}
int jup(int x,int w){
for(int i=20;i>=0;i--){
if(f[x][i]==0||W[f[x][i]]>w)continue;
x=f[x][i];
}
return x;
}
int get_lca(int x,int y){
if(deep[x]<deep[y])swap(x,y);
for(int i=20;i>=0;i--){
if(deep[f[x][i]]>=deep[y])x=f[x][i];
}
if(x==y)return x;
for(int i=20;i>=0;i--){
if(f[x][i]!=f[y][i]){
x=f[x][i],y=f[y][i];
}
}
return f[x][0];
}
void build_tree(){
sort(ed+1,ed+1+m,cmp_1);
for(int i=1;i<=n;i++)fa[i]=i;
for(int i=1;i<=m;i++){
int x=find(ed[i].u),y=find(ed[i].v);
if(x==y)continue;
tot++;
fa[x]=fa[y]=fa[tot]=tot;
f[x][0]=f[y][0]=tot;
add_edge(tot,x);add_edge(tot,y);
W[tot]=ed[i].w;
}
root=tot;
tot=0;
deep[root]=1;
get_dfn(root);
cnt=0;
for(int i=1;i<=tot;i++)head[i]=0;
tot=0;
}
void rebuild_tree(){
for(int i=1;i<=n;i++){
if(vec[i].size()){
a[0]=0;
for(int j=0;j<vec[i].size();j++){
a[++a[0]]=vec[i][j];
sort(a+1,a+1+a[0],cmp_2);
}
stack[top=1]=root;
id[++tot]=root;Map[root]=tot;
for(int j=1;j<=a[0];j++){
int p=a[j];
int lca=get_lca(stack[top],p);
if(lca==stack[top])stack[++top]=p,id[++tot]=p;
else{
while(top>1&&dfn[stack[top-1]]>dfn[lca]){fa[Map[stack[top]]]=Map[stack[top-1]],top--;}
if(dfn[stack[top-1]]<dfn[lca]){id[++tot]=lca;Map[lca]=tot;fa[Map[stack[top]]]=Map[lca];stack[top]=lca;}
stack[++top]=p;id[++tot]=p;
}
Map[p]=tot;
}
while(top>1)fa[Map[stack[top]]]=Map[stack[top-1]],top--;
for(int j=1;j<=a[0];j++)change(Map[a[j]],val[a[j]],0);
}
}
}
void clear(){
for(int i=1;i<=n;i++)vec[i].clear();
for(int i=1;i<=tot;i++)mx[i]=0;
for(int i=1;i<=Size[root];i++)tr[i]=0,W[i]=0;
for(int i=1;i<=Size[root];i++)
for(int j=0;j<=20;j++)f[i][j]=0;
}
signed main(){
int T=read();
while(T--){
n=read(),m=read();
int q=read();
for(int i=1;i<=n;i++)c[i]=read(),vec[c[i]].push_back(i);
for(int i=1;i<=n;i++)val[i]=read();
tot=n;
for(int i=1;i<=m;i++)
ed[i].u=read(),ed[i].v=read(),ed[i].w=read();
build_tree();
rebuild_tree();
while(q--){
int type=read(),x=read(),y=read();
if(type==0){
change(Map[x],val[x]+y,val[x]);
val[x]+=y;
}
if(type==1){
int Top=jup(x,y);
printf("%lld\n",get_sum(dfn[Top]+Size[Top]-1)-get_sum(dfn[Top]-1));
}
}
clear();
}
return 0;
}