【树上模拟】
【树上模拟】
1-1-1, Free Tree!
https://codeforces.com/contest/2126/problem/F
树很关键的一个优化点:父亲有且只有一个
->将遍历出边O(n)优化到:遍历父亲O(1)/儿子(如果可以一起维护)
题目大意
思路
难点在于每次修改颜色之后需要遍历所有出边的点来修改
->如果变成只修改父亲呢?
代码
const int N=2e5+10;
int n,q;
vector<PII> g[N];
map<int,i64> p[N];//颜色,花销
int a[N];
int fa[N];
void init(int x){
for(int i=1;i<=x;i++){
for(auto &[key,val]:p[i]){
val=0;
}
p[i].clear();
g[i].clear();
a[i]=0;
fa[i]=i;
}
}
//对于一个点,他的所有子节点我可以直接维护 父节点单独判断
void dfs(int u,int f){
fa[u]=f;
for(auto son:g[u]){
int pos=son.fi;
i64 val=son.sc;
if(pos!=f){
p[u][a[pos]]+=val;
dfs(pos,u);
}
}
}
void solve(){
cin>>n>>q;
init(n);
for(int i=1;i<=n;i++) cin>>a[i];
i64 ans=0;
map<pair<int,int>,i64> bian;
for(int i=1;i<n;i++){
int u=0,v=0;
i64 c=0;
cin>>u>>v;
cin>>c;
if(a[u]!=a[v]) ans+=c;
g[u].push_back({v,c});
g[v].push_back({u,c});
if(u>v) swap(u,v);
bian[{u,v}]=c;
}
dfs(1,0);
while(q--){
int v,x;
cin>>v>>x;
if(a[v]==x){
cout<<ans<<endl;
continue;
}
//非叶节点
if(v!=1){
if(x==a[fa[v]] && a[v]!=a[fa[v]]){
ans-=bian[{min(v,fa[v]),max(v,fa[v])}];
}
else if(a[v]==a[fa[v]] && x!=a[fa[v]]){
ans+=bian[{min(v,fa[v]),max(v,fa[v])}];
}
}
ans+=p[v][a[v]];
ans-=p[v][x];
if(v!=1){
p[fa[v]][a[v]]-=bian[{min(v,fa[v]),max(v,fa[v])}];
p[fa[v]][x]+=bian[{min(v,fa[v]),max(v,fa[v])}];
}
a[v]=x;
cout<<ans<<endl;
}
}