CF2006B Iris and the Tree
CF2006B Iris and the Tree
人类智慧!不过是水题一道。
题意简述: 给一棵以 1 为根的树,满足结点编号为 DFS 序。现在一次给出一些边权。每次给出后,剩下的边权自定义,输出满足 \(\sum w(e)=K\) 的同时所有 \(\max\{dist(x,x\%n+1)\}\) 的和。
数据范围:\(2\ le n \le 200000\) 。
Solution
我们约定 \(d(x)=dist(x,x\%n+1)\) 。
这个树有很不一样的性质,我们考虑每次给出边权后对答案的影响。我们发现修改的路径其实很少。
由于 DFS 序的性质,\((x,y)\) 只会修改进入 \(subtree(y)\) 的路径和出去的路径,即 \(d(x-1)\) 和 \(d(\max_{p\in subtree(y)}\{p\})\) 。
我们只用修改这两条路径的权值。
对于每个答案,我们贪心得让剩下得边权全部填进去,即 \(K-sum+val(x)\)。\(val(x)\) 为题目放入得边权和,\(sum\) 为所有的边权和。
每次放入边权,其他所有的路径都会对应减少 \(w(e)\) ,原因是 \(w(e)\) 被占用。
每次随便删除加入维护即可。
P.S. 由于本题输入特别优秀,所以同样优秀的写法可以减少大量编程复杂度。
代码如下:
#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const int N=2e5+10,M=N*2;
int head[N],ver[M],nxt[M],tot=1;
void add(int x,int y){
ver[++tot]=y,nxt[tot]=head[x],head[x]=tot;
}
ll m;
int n,fa[N][21],R[N];
ll len[N],d[N];
ll cnt[N],val[N];
ll ans,sum,unfilled;
void dfs(int x,int fa){
R[x]=x;
for(int i=head[x];i;i=nxt[i]){
int y=ver[i];
if(y==fa)continue;
dfs(y,x);
R[x]=max(R[x],R[y]);
}
}
int LCA(int x,int y){
if(x==y)return x;
if(d[x]<d[y])swap(x,y);
for(int i=19;~i;i--)
if(d[fa[x][i]]>=d[y])x=fa[x][i];
if(x==y)return x;
for(int i=19;~i;i--)
if(fa[x][i]!=fa[y][i])
x=fa[x][i],y=fa[y][i];
return fa[x][0];
}
ll calc(int x){
if(cnt[x]==len[x])return val[x];
else return m-(sum-val[x]);
}
void solve(){
scanf("%d%lld",&n,&m);
for(int i=0;i<=n;i++)head[i]=0;
tot=1;
d[1]=1;
for(int i=2;i<=n;i++){
int pi;scanf("%d",&pi);
fa[i][0]=pi;
d[i]=d[pi]+1;
add(i,pi),add(pi,i);
}
for(int i=1;i<20;i++)
for(int x=1;x<=n;x++)
fa[x][i]=fa[fa[x][i-1]][i-1];
for(int i=1;i<=n;i++){
int x=i,y=i%n+1;
len[i]=d[x]+d[y]-2ll*d[LCA(x,y)];
}
ans=0,sum=0,unfilled=n;
dfs(1,0);
for(int i=1;i<=n;i++)cnt[i]=val[i]=0,ans+=calc(i);
for(int i=1;i<n;i++){
ll x,y;
scanf("%lld%lld",&x,&y);
ans-=calc(x-1)+calc(R[x]);
if(++cnt[x-1]==len[x-1])--unfilled;
val[x-1]+=y;
if(++cnt[R[x]]==len[R[x]])--unfilled;
val[R[x]]+=y;
sum+=y,ans-=y*(unfilled-(cnt[x-1]!=len[x-1])-(cnt[R[x]]!=len[R[x]]));
ans+=calc(x-1)+calc(R[x]);
printf("%lld ",ans);
}
puts("");
for(int i=0;i<20;i++)
for(int x=1;x<=n;x++)
fa[x][i]=0;
}
int main(){
int T;scanf("%d",&T);
while(T--)solve();
return 0;
}

浙公网安备 33010602011771号