[WC2013] 糖果公园
真是品鉴了一个大的。第一道树上莫队题。
题目思路
带修树上莫队。
还是随便放一点树上莫队的知识点吧。
利用欧拉序将树上路径变为序列,其中 \(st_u\) 是第一次出现位置,\(en_u\) 是第二次出现位置。
假设 \(st_x<st_y\)。令 \(ll=lca(x,y)\):
若 \(ll=u\),此时路径 \(u\) 到 \(v\) 对应欧拉序区间:\([ st_u, st_v ]\)。
否则对应欧拉序区间:\([ en_u, st_v ]\)。并且还要加上 \(ll\)。
维护莫队时,由于每个点出现两次,所以这个状态更新是类似于异或的:
void deal(int x){
if(used[x]) remove(x);
else add(x);
used[i]^=1;
}
大概就这么多。
回到这道题,好像也没什么难的嘛比较板子,就是还有修改。
🍭🍭错误:传参混淆;存欧拉序的数组忘两倍。
AC Code
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+5;
int n,m,ln,q,v[N],w[N],fat[N][25],c[N],qcnt,rcnt,ans[N];
int st[N],en[N],tim,dth[N],tot,el[N<<2],EL,Cnt[N],cc[N];
bool vis[N];
vector<int>g[N];
struct node{
int t,l,r,ex,id;
bool operator < (const node& s1)const{
if(s1.l/ln!=l/ln) return l<s1.l;
if(s1.r/ln!=r/ln) return r<s1.r;
return t<s1.t;
}
}qr[N];
struct str{
int w,ps,to;
}r[N];
void dfs(int u,int fa){
fat[u][0]=fa;st[u]=++tim;el[++EL]=u;dth[u]=dth[fa]+1;
for(int i=1;i<=24;i++)
fat[u][i]=fat[fat[u][i-1]][i-1];
for(int v:g[u]){
if(v==fa) continue;
dfs(v,u);
}
en[u]=++tim;
el[++EL]=u;
}
int lca(int x,int y){
if(dth[x]<dth[y]) swap(x,y);
for(int i=24;i>=0;i--){
if(dth[x]-(1<<i)>=dth[y]) x=fat[x][i];
}
if(x==y) return x;
for(int i=24;i>=0;i--){
if(fat[x][i]!=fat[y][i]){
x=fat[x][i];y=fat[y][i];
}
}
return fat[x][0];
}
void add(int x){
Cnt[x]++;
tot+=w[Cnt[x]]*v[x];
}
void del(int x){
tot-=w[Cnt[x]]*v[x];
Cnt[x]--;
}
void deal(int x){
if(vis[x]) del(c[x]);
else add(c[x]);
vis[x]^=1;
}
void hs(){
sort(qr+1,qr+qcnt+1);
for(int i=1,L=1,R=0,last=0;i<=qcnt;i++){
while(L>qr[i].l) deal(el[--L]);
while(R<qr[i].r) deal(el[++R]);
while(L<qr[i].l) deal(el[L++]);
while(R>qr[i].r) deal(el[R--]);
while(last<qr[i].t){
last++;
int x=r[last].w;
if(vis[x]){
del(c[x]);
add(r[last].to);
}
c[x]=r[last].to;
}
while(last>qr[i].t){
int x=r[last].w;
if(vis[x]){
del(c[x]);
add(r[last].ps);
}
c[x]=r[last].ps;
last--;
}
ans[qr[i].id]=tot;
if(qr[i].ex!=0){
Cnt[c[qr[i].ex]]++;
ans[qr[i].id]+=v[c[qr[i].ex]]*w[Cnt[c[qr[i].ex]]];
Cnt[c[qr[i].ex]]--;
}
}
}
signed main(){
ios::sync_with_stdio(0),cin.tie(0);
cin>>n>>m>>q;
ln=pow(n*2,2.0/3.0);
for(int i=1;i<=m;i++) cin>>v[i];
for(int i=1;i<=n;i++) cin>>w[i];
for(int i=1,u,v;i<n;i++){
cin>>u>>v;
g[u].push_back(v);
g[v].push_back(u);
}
dfs(1,0);
for(int i=1;i<=n;i++) cin>>c[i],cc[i]=c[i];
for(int i=1,op,x,y,L=0,R=0,ex=0;i<=q;i++){
cin>>op>>x>>y;
if(op){
//根据(x,y)算出L,R,ex
if(st[x]>st[y]) swap(x,y);
int ll=lca(x,y);
if(x==ll){
L=st[x];R=st[y];ex=0;
}
else{
L=en[x];R=st[y];ex=ll;
}
qcnt++;qr[qcnt]={rcnt,L,R,ex,qcnt};
}
else{
r[++rcnt]={x,cc[x],y};
cc[x]=y;
}
}
hs();
for(int i=1;i<=qcnt;i++) cout<<ans[i]<<"\n";
return 0;
}
古顾故

浙公网安备 33010602011771号