题解:P9638 「yyOI R1」youyou 的军训
P9638 题解
题面
题意
给定一个 \(n\) 个点 \(m\) 条边的图以及 \(q\) 个操作,有以下 \(3\) 种情况:
1 x,恢复以前所有的边,并删去 \(\leqslant x\) 的所有边。2 x,询问 \(x\) 包括自己的能连到的点的个数。3 x w,把第 \(x\) 条边的边权改为 \(w\),并且不改变这条边权值的相对排名。
思路
看到这道题,想到操作 1 的删去 \(\leqslant x\) 的所有边,即留下所有 \(>x\) 的所有边,而且每次改变权值都不改变相对排名,这不仅让人想到瓶颈路,于是想到 kruskal 重构树。
这道题留下所有 \(>x\) 的所有边则是用 kruskal 重构树跑出最大生成树的重构树。
则到点 \(x\) 的简单路径上最大边权的最小值 \(>val\) 的所有点 \(y\) 均在 kruskal 重构树上的某一棵子树内,且恰好为该子树的所有叶子节点。
于是这一题就可以做了,只要在重构树上统计每个点的子树的叶子节点个数就可以了,对于询问则是可以选择倍增,找到深度最浅的 \(\leqslant tmp\) 的点(\(tmp\) 为上一次 1 操作的 \(x\))。
后记
- 题目没有保证图是一个连通块,所以需要按照数据有多个连通块来处理。
- 由于是在下一个操作
1才能恢复上一个操作1断开的边,所以应该用一个队列把修改操作3存下来,然后每一个操作1的之后执行与之前那一个操作1之间的所有操作3。不过呢,这题的数据并没有针对这个来卡,我也很失望,具体的可以参照这个帖子。
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
//#define gc getchar
#define gc()(p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
#define ll long long
#define pll pair<ll,ll>
using namespace std;
const int MN=1e6+5;
ll n,m,Q,tot,head[MN],idx,f[MN],fa[MN][20],val[MN],tmp,son[MN],to[MN];
queue<pll> q;
struct edge1{ll to,nxt;}e[MN];
struct edge2{ll u,v,w,id;}E[MN];
char buf[1<<23],*p1=buf,*p2=buf;
void write(ll n){if(n<0){putchar('-');write(-n);return;}if(n>9)write(n/10);putchar(n%10+'0');}
ll read(){ll x=0,f=1;char ch=gc();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=gc();}while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=gc();}return x*f;}
bool cmp(edge2 a, edge2 b){return a.w>b.w;}
void add(ll u, ll v){e[++tot].nxt=head[u];head[u]=tot;e[tot].to=v;}
ll find(ll x){return x==f[x]?x:f[x]=find(f[x]);}
void kruskal(){
for(int i=1; i<=2*n; i++) f[i]=i;
sort(E+1,E+1+m,cmp);
for(int i=1; i<=m; i++){
ll u=find(E[i].u),v=find(E[i].v);
if(u==v) continue;
val[++idx]=E[i].w;f[u]=f[v]=fa[u][0]=fa[v][0]=to[E[i].id]=idx;
add(idx,u);add(idx,v);
if(idx-n==n-1) break;
}
}
void dfs(ll u){
for(int i=1; i<20; i++) fa[u][i]=fa[fa[u][i-1]][i-1];
if(!head[u]){son[u]=1;return;}
for(int i=head[u]; i; i=e[i].nxt){
ll v=e[i].to;
dfs(v);
son[u]+=son[v];
}
}
ll query(ll x){
for(int i=19; ~i; i--) if(fa[x][i]&&val[fa[x][i]]>=tmp) x=fa[x][i];
return son[x];
}
int main(){
//ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
idx=n=read();m=read();Q=read();
for(int i=1; i<=m; i++) E[i].u=read(),E[i].v=read(),E[i].w=read(),E[i].id=i;
kruskal();
for(int i=idx; i; i--) if(!son[i]) dfs(i);
while(Q--){
ll op=read();
if(op==1){
tmp=read();
while(!q.empty()){
pll top=q.front();q.pop();
val[to[top.first]]=top.second;
}
}
if(op==2){ll x=read();write(query(x));putchar('\n');}
if(op==3){ll x=read(),w=read();q.push({x,w});}
}
return 0;
}//250518

浙公网安备 33010602011771号