C115 树上莫队 P4074 [WC2013] 糖果公园
视频链接:C115 树上莫队 P4074 [WC2013] 糖果公园_哔哩哔哩_bilibili
D11 树链剖分 P3379【模板】最近公共祖先(LCA) - 董晓 - 博客园 (cnblogs.com)
C113 带修莫队 P1903 [国家集训队] 数颜色/维护队列 - 董晓 - 博客园 (cnblogs.com)
// 树上莫队 O(n^(5/3)) #include <iostream> #include <cstring> #include <algorithm> #include <cmath> using namespace std; #define LL long long const int N=200005; int head[N],to[N],ne[N],idx; void link(int u,int v){ //连边 to[++idx]=v;ne[idx]=head[u];head[u]=idx; } int fa[N],son[N],siz[N],dep[N],top[N]; int tim,in[N],out[N],a[N<<1]; void dfs1(int u,int f){ //树链剖分 fa[u]=f;siz[u]=1;dep[u]=dep[f]+1; for(int i=head[u];i;i=ne[i]){ int v=to[i]; if(v==f) continue; dfs1(v,u); siz[u]+=siz[v]; if(siz[son[u]]<siz[v])son[u]=v; } } void dfs2(int u,int t){ in[u]=++tim; //进u时刻 a[tim]=u; //括号序 top[u]=t; if(son[u]) dfs2(son[u],t); for(int i=head[u];i;i=ne[i]){ int v=to[i]; if(v==fa[u]||v==son[u])continue; dfs2(v,v); } out[u]=++tim; //出u时刻 a[tim]=u; //括号序 } int LCA(int u,int v){ while(top[u]!=top[v]){ if(dep[top[u]]<dep[top[v]])swap(u,v); u=fa[top[u]]; } return dep[u]<dep[v]?u:v; } int n,m,k,B,tot,V[N],W[N],C[N]; int pos[N],newC[N],vis[N],cnt[N]; LL ans[N],sum; struct Q{ int l,r,t,id,lca; bool operator<(Q &b){ if(l/B!=b.l/B)return l<b.l; if(r/B!=b.r/B)return r<b.r; return t<b.t; } }q[N]; void add(int x){ vis[x]^=1; //访问x点的次数 // 一次扩展 加上贡献,两次扩展 减去贡献 if(vis[x]) sum+=1ll*W[++cnt[C[x]]]*V[C[x]]; else sum-=1ll*W[cnt[C[x]]--]*V[C[x]]; } int main(){ scanf("%d%d%d",&n,&m,&k); //点,糖果种类,操作 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,u,v;i<n;++i) //连边 scanf("%d%d",&u,&v),link(u,v),link(v,u); // 预处理括号序和LCA dfs1(1,0);dfs2(1,1); for(int i=1;i<=n;++i)scanf("%d",&C[i]);//糖果类型 // 预处理操作 for(int i=1,t=0,Type,x,y;i<=k;++i){ scanf("%d%d%d",&Type,&x,&y); if(Type==1){ //区查 int lca=LCA(x,y); q[++tot].t=t; q[tot].id=tot; if(in[x]>in[y])swap(x,y); //先x后y if(lca==x){ //直链情况 q[tot].l=in[x]; q[tot].r=in[y]; } else{ //折链情况 q[tot].l=out[x]; q[tot].r=in[y]; q[tot].lca=lca; //以便补偿 } } else{ //点修 pos[++t]=x; //位置 newC[t]=y; //修改值 } } // 树上带修莫队 B=pow(2*n,0.66); sort(q+1,q+tot+1); for(int i=1,l=1,r=0,t=0;i<=tot;++i){ while(l>q[i].l)add(a[--l]); while(r<q[i].r)add(a[++r]); while(l<q[i].l)add(a[l++]); while(r>q[i].r)add(a[r--]); while(t<q[i].t){ //时间戳变大则替换 ++t; if(vis[pos[t]]){ add(pos[t]); swap(C[pos[t]],newC[t]); //换成修改值 add(pos[t]); } else swap(C[pos[t]],newC[t]); } while(t>q[i].t){ //时间戳变小则还原 if(vis[pos[t]]){ add(pos[t]); swap(C[pos[t]],newC[t]); //还原修改值 add(pos[t]); } else swap(C[pos[t]],newC[t]); t--; } ans[q[i].id]=sum; if(q[i].lca) ans[q[i].id]+= //补上lca的 1ll*W[cnt[C[q[i].lca]]+1]*V[C[q[i].lca]]; } for(int i=1;i<=tot;++i)printf("%lld\n",ans[i]); }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!