luogu P3665 [USACO17OPEN]Switch Grass P
在一道题里面写错两次并查集我真的会屑。
无向图的路径显然不是很好做的亚子,考虑如果这条路径不是一条边,那么这条路径上一定有一条边可以代替这条路径并且权值更小。因此可以转化成找到最小的两端点异色的边。
其次这条边一定在最小生成树上,因为同上,如果一条不在最小生成树上的边两端点异色,那么代表最小生成树上存在一条路径两端点异色,因为这条边不在最小生成树上因此任意一条路径上的边都可以代替这条边,所以这条边永远不可能是答案。
现在问题转化成树上每次修改一个点的颜色,问一条两端点异色的边的权值最小值。
本来看上去很根号分治,但是根号分治肯定要带log因此不是很跑的过去。考虑每个点和父节点的边。先在父节点上开一个map套set表示这个父节点儿子中每种颜色对应的权值。然后修改只会改到这个点和父节点的答案,因此可以\(O(\log n)\)修改。
时间复杂度\(O(m\log m+q\log n)\)
code:
#include<bits/stdc++.h>
#define Gc() getchar()
#define Me(x,y) memset(x,y,sizeof(x))
#define Mc(x,y) memcpy(x,y,sizeof(x))
#define d(x,y) ((m)*(x-1)+(y))
#define R(n) (rnd()%(n))
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound
#define PB push_back
using ll=long long;using db=double;using lb=long db;using ui=unsigned;using ull=unsigned ll;
using namespace std;const int N=4e5+5,M=(N<<2)+5,K=(1<<10)+5,mod=1e9+7,Mod=mod-1;ll INF=1e18+7;const db eps=1e-5;mt19937 rnd(time(0));
int n,m,k,q,fa[N],A[N],W[N],x,y;map<int,multiset<int>> f[N];multiset<int> g;
struct Node{int to,w;};vector<Node> S[N];
struct Edge{int x,y,w;}P[N];bool cmp(Edge x,Edge y){return x.w<y.w;}
int GF(int x){return fa[x]^x?fa[x]=GF(fa[x]):x;}
void Ins(int x){
if(f[x].count(A[x])&&f[x][A[x]].size()) assert(g.LB(*f[x][A[x]].begin())!=g.end()),g.erase(g.LB(*f[x][A[x]].begin()));if(!fa[x]) return;
if(A[x]^A[fa[x]]){
if(!f[fa[x]][A[x]].size()) g.insert(W[x]);
else if(*f[fa[x]][A[x]].begin()>W[x]) g.erase(g.LB(*f[fa[x]][A[x]].begin())),g.insert(W[x]);
} f[fa[x]][A[x]].insert(W[x]);
}
void Del(int x){
if(f[x].count(A[x])&&f[x][A[x]].size()) g.insert(*f[x][A[x]].begin());if(!fa[x]) return;
f[fa[x]][A[x]].erase(f[fa[x]][A[x]].LB(W[x]));if(A[x]^A[fa[x]]){
if(!f[fa[x]][A[x]].size()) g.erase(g.LB(W[x]));
else if(*f[fa[x]][A[x]].begin()>W[x])g.erase(g.LB(W[x])),g.insert(*f[fa[x]][A[x]].begin());
}
}
void Make(int x,int La){fa[x]=La;Ins(x);for(Node i:S[x]) i.to^La&&(W[i.to]=i.w,Make(i.to,x),0);}
int main(){
freopen("1.in","r",stdin);
int i,j;scanf("%d%d%d%d",&n,&m,&k,&q);for(i=1;i<=m;i++) scanf("%d%d%d",&P[i].x,&P[i].y,&P[i].w);sort(P+1,P+m+1,cmp);for(i=1;i<=n;i++) fa[i]=i;
for(i=1;i<=m;i++) GF(P[i].x)^GF(P[i].y)&&(S[P[i].x].PB((Node){P[i].y,P[i].w}),S[P[i].y].PB((Node){P[i].x,P[i].w}),fa[GF(P[i].x)]=GF(P[i].y));
for(i=1;i<=n;i++) scanf("%d",&A[i]);Make(1,0);while(q--){
scanf("%d%d",&x,&y);Del(x);A[x]=y;Ins(x);printf("%d\n",*g.begin());//printf("%d\n",f[2][3].size());
}
}