题解:P9638 「yyOI R1」youyou 的军训
先放一个帖子:link。
这题有一个细节,后面再说。
首先我们发现这个题面十分抽象,所以先提取关键信息,发现没有
考虑 Kruskal 重构树,则每次能走到的点对应到重构树上刚好就是一个子树,因为 LCA 肯定是瓶颈,既然 LCA 都能走,子树内一定畅通无阻。
那这个方法对于有 不然我为啥讲。
发现权值的相对关系始终不变,所以树的形态也一定不会变,所以每次修改边权就直接修改 LCA 的点权就行了,不过要提前判断这条边是否在 Kruskal 重构树上,否则只有
然后就牵扯到上面的帖子了,题面中说了修改边权不会是断掉的边是不会重连的,所以有些题解的代码有点问题。
具体实现
还有就是这道题你不管操作
#include<bits/stdc++.h>
using namespace std;
namespace Fread {
const int SIZE=1<<21;char buf[SIZE],*S,*T;
inline char getchar() {if(S==T){T=(S=buf)+fread(buf,1,SIZE,stdin);if(S==T)return '\n';}return *S++;}
}
namespace Fwrite {
const int SIZE=1<<21;
char buf[SIZE],*S=buf,*T=buf+SIZE;
inline void flush(){fwrite(buf,1,S-buf,stdout);S=buf;}
inline void putchar(char c){*S++=c;if(S==T)flush();}
struct POPOSSIBLE{~POPOSSIBLE(){flush();}}ztr;
}
#define getchar Fread :: getchar
#define putchar Fwrite :: putchar
namespace Fastio{
struct Reader{
template<typename T>
Reader& operator >> (T& x) {
char c=getchar();T f=1;
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}x=0;
while(c>='0'&&c<='9'){x=x*10+(c-'0');c=getchar();}x*=f;
return *this;
}
Reader(){}
}cin;
struct Writer{
template<typename T>
Writer& operator << (T x) {
if(x==0){putchar('0');return *this;}
if(x<0){putchar('-');x=-x;}
static int sta[45];int top=0;
while(x){sta[++top]=x%10;x/=10;}
while(top){putchar(sta[top]+'0');--top;}
return *this;
}
Writer& operator << (char c) {putchar(c);return *this;}
Writer& operator << (const char* str){int cur=0;while(str[cur])putchar(str[cur++]);return *this;}
Writer(){}
}cout;
}
#define fi first
#define endl '\n'
#define sec second
#define mk make_pair
#define cin Fastio :: cin
#define cout Fastio :: cout
const int B=20;
const int N=1e6+10;
typedef pair<int,int> pii;
struct edge{
int x,y,z;
edge(int x=0,int y=0,int z=0):x(x),y(y),z(z){;}
bool operator <(const edge &t)const{return z>t.z;}
}a[N],b[N];
int siz[N],f[N][B+1],fa[N],ls[N],rs[N],tot,n,m,q,w[N],las,dep[N];
int root(int x){return x==fa[x]?x:fa[x]=root(fa[x]);}
vector < pii > Q;
void Kruskal(){
sort(a+1,a+1+m);
for(int i=1;i<=m;++i){
int x=root(a[i].x);
int y=root(a[i].y);
if(x==y) continue;
w[++tot]=a[i].z;
fa[x]=fa[y]=tot;
ls[tot]=x;rs[tot]=y;
}
}
void dfs(int x,int y){
f[x][0]=y;dep[x]=dep[y]+1;
for(int i=1;i<=B;++i) f[x][i]=f[f[x][i-1]][i-1];
if(x<=n) siz[x]=1;
else {
dfs(ls[x],x);dfs(rs[x],x);
siz[x]=siz[ls[x]]+siz[rs[x]];
}
}
inline int LCA(int x,int y){
if(dep[x]<dep[y]) swap(x,y);
for(int i=B;~i;--i) if(dep[f[x][i]]>=dep[y]) x=f[x][i];
if(x==y) return x;
for(int i=B;~i;--i) if(f[x][i]!=f[y][i]){x=f[x][i];y=f[y][i];}
return f[x][0];
}
inline int jump(int x){
for(int i=B;~i;--i) if(f[x][i]&&w[f[x][i]]>=las) x=f[x][i];
return siz[x];
}
int main(){
cin>>n>>m>>q;tot=n;
for(int i=1;i<=(n<<1);++i) fa[i]=i;
for(int i=1;i<=m;++i) cin>>a[i].x>>a[i].y>>a[i].z;
for(int i=1;i<=m;++i) b[i]=a[i];Kruskal();
for(int i=tot;i;--i) if(!siz[i]) dfs(i,0);
for(int i=1,opt,x,y;i<=q;++i){
cin>>opt>>x;
if(opt==1){for(auto i:Q) w[i.fi]=i.sec;Q.clear();las=x;}
else if(opt==2) cout<<jump(x)<<endl;
else {
cin>>y;
int lca=LCA(b[x].x,b[x].y);
if(w[lca]!=b[x].z) continue;
Q.emplace_back(lca,b[x].z=y);
}
}
return 0;
}
//这条边有可能本来就没影响。输。