专栏文章
CF1797D
CF1797D题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @min1zdie
- 此快照首次捕获于
- 2025/12/01 19:15 3 个月前
- 此快照最后确认于
- 2025/12/01 19:15 3 个月前
Accepted。
题解
他提到重儿子,所以不要树链剖分。令 为 的重儿子, 为 的父节点。
对于操作 1,dfs 一遍预处理一个数组 存以 为根的子树重要度和。
对于操作 2,发现其只会影响 ,,,所以只需要操作 个点,考虑动态维护节点 的儿子。
操作 2 的具体过程其实是: 变为 的儿子之一, 变为 的儿子之一。
然后就是对 和 进行修改。
其中 ,, 同理。
此时 ,, 的儿子都会发生变化。
在 的儿子中删去 ,在 的儿子中删去 ,在 的儿子中删去 并添加 ,这用一个 set 便可以解决(set 的排序功能还可以帮助找 )。
此题结。
代码
CPP#include<bits/stdc++.h>
#define pii pair<int,int>
#define ll long long
using namespace std;
const int N=1e5+5;
int n,m;
int head[N],to[2*N],nxt[2*N],idx;
int siz[N],fa[N];
ll s[N],a[N];
set<pii> son[N];
inline void add(int x,int y) {
nxt[++idx]=head[x],head[x]=idx,to[idx]=y;
return;
}
void dfs(int x) {
siz[x]=1,s[x]=a[x];
for(int i=head[x];i;i=nxt[i]) {
int y=to[i];
if(y!=fa[x]) {
fa[y]=x;
dfs(y);
siz[x]+=siz[y],s[x]+=s[y];
son[x].insert({-siz[y],y});
}
}
return;
}
int main() {
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
for(int i=1,x,y;i<n;i++) scanf("%d%d",&x,&y),add(x,y),add(y,x);
dfs(1);
while(m--) {
int op,x;
scanf("%d%d",&op,&x);
if(op==1) printf("%lld\n",s[x]);
if(op==2) {
if(son[x].empty()) continue;
int hv=(*son[x].begin()).second;
son[fa[x]].erase(son[fa[x]].find({-siz[x],x}));
s[x]-=s[hv],s[hv]+=s[x];
siz[x]-=siz[hv],siz[hv]+=siz[x];
son[hv].insert({-siz[x],x});
son[fa[x]].insert({-siz[hv],hv});
son[x].erase(son[x].begin());
fa[hv]=fa[x],fa[x]=hv;
}
}
return 0;
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...