有一个有 n n n个点 n n n条边的无向连通图,一开始每条边都有一个颜色 c c c。
有 m m m次操作,每次操作将一条两个端点为 x , y x,y x,y的边的颜色修改为 c c c。求每次修改之后,图中有多少个颜色相同的连通块。
一个颜色相同的连通块指的是一个由一些相同颜色的边组成的连通块。
有 T T T组数据。
1 ≤ T ≤ 10 , 3 ≤ n , m ≤ 1 0 5 , 1 ≤ c ≤ n 1\leq T\leq 10,3\leq n,m\leq 10^5,1\leq c\leq n 1≤T≤10,3≤n,m≤105,1≤c≤n
我们可以发现,这个图是一个基环树。
下面先考虑这个图是一棵树的情况。
我们考虑将一条边的修改看成给这条边删去颜色和给这条边加上颜色两个部分,那么一开始加边时处理边的颜色也可以看作给没有颜色的边加上颜色。
我们先考虑删去一条边的颜色对答案的贡献,设这条边的两个端点为 x , y x,y x,y,颜色为 c c c:
再考虑加上一条边的颜色对答案的贡献,设这条边的两个端点为 x , y x,y x,y,颜色为 c c c:
而当这个图是基环树的时候,有一些特殊情况需要特判:
我们先找出环,然后按上面说的做就可以了。
注意在查找两个端点为 x , y x,y x,y的边的编号和每个点是否有每种颜色的边的时候,可以用 m a p map map来储存。
时间复杂度为 O ( n log n ) O(n\log n) O(nlogn)。
#include
using namespace std;
const int N=100000;
int T,n,m,tot,d[2*N+5],l[2*N+5],r[N+5],c[N+5];
int ans,top,st[N+5],lp[N+5],dep[N+5],z[N+5],sum[N+5];
map<int,int>mp[N+5],hv[N+5];
struct node{
int x,y,v;
}w[N+5];
void add(int xx,int yy){
l[++tot]=r[xx];d[tot]=yy;r[xx]=tot;
}
void dfs(int u,int fa){
dep[u]=dep[fa]+1;
st[++top]=u;
for(int i=r[u];i;i=l[i]){
if(d[i]==fa) continue;
if(dep[d[i]]&&dep[d[i]]<dep[u]){
while(st[top]!=d[i]){
lp[++lp[0]]=st[top];--top;
}
lp[++lp[0]]=d[i];
}
if(!dep[d[i]]) dfs(d[i],u);
}
if(st[top]==u) --top;
}
void pt(int x,int y,int v,int zt){
int tmp=(hv[x][v]!=0)+(hv[y][v]!=0);
++hv[x][v];++hv[y][v];
if(zt) ++sum[v];
if(zt&&sum[v]==lp[0]) --tmp;
ans+=1-tmp;
}
void del(int x,int y,int v,int zt){
--hv[x][v];--hv[y][v];
int tmp=(hv[x][v]!=0)+(hv[y][v]!=0);
if(zt&&sum[v]==lp[0]) --tmp;
if(zt) --sum[v];
ans-=1-tmp;
}
int main()
{
freopen("tour.in","r",stdin);
freopen("tour.out","w",stdout);
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
tot=0;ans=0;
for(int i=0;i<=N;i++){
r[i]=dep[i]=z[i]=c[i]=sum[i]=0;
mp[i].clear();
hv[i].clear();
}
for(int i=1,x,y,v;i<=n;i++){
scanf("%d%d%d",&x,&y,&v);
w[i]=(node){x,y,v};
add(x,y);add(y,x);
mp[x][y]=mp[y][x]=i;
}
top=0;lp[0]=0;dfs(1,0);
for(int i=1,x,y;i<=lp[0];i++){
x=lp[i];y=lp[i%lp[0]+1];
z[mp[x][y]]=1;
}
for(int i=1;i<=n;i++){
pt(w[i].x,w[i].y,w[i].v,z[i]);
c[i]=w[i].v;
}
for(int i=1,x,y,v,p;i<=m;i++){
scanf("%d%d%d",&x,&y,&v);
p=mp[x][y];
del(x,y,c[p],z[p]);
pt(x,y,v,z[p]);
c[p]=v;
printf("%d\n",ans);
}
}
return 0;
}