Loading

CF1166F Vicky's Delivery Service

最近太摆了,写一篇题解。

只走偶数步是很好处理的,直接用map存一下之后上并查集。

主要是还有奇数步,这个的话就可以用set存每个连通块可以小于等于一步走到的点了。

当然合并的时候要把set也合并上,用启发式合并就好了,反正存的东西 \(\le m\)

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
map<int,int>id[N];
map<int,vector<int>>e[N];
int n,m,c,q,tot,f[N*10];
set<int>s[N*10];
int find(int x)
{
    if(f[x]==x)return x;
    return f[x]=find(f[x]);
}
void merge(int x,int y)
{
    x=find(x),y=find(y);
    if(x==y)return;
    if(s[x].size()<s[y].size())swap(x,y);
    for(int t:s[y])s[x].insert(t);
    f[y]=x;
    return;
}
int main()
{
    scanf("%d%d%d%d",&n,&m,&c,&q),tot=n;
    for(int i=1;i<=n;i++)f[i]=i,s[i].insert(i);
    for(int i=1,u,v,w;i<=m;i++)
    {
        scanf("%d%d%d",&u,&v,&w);
        e[u][w].push_back(v);
        e[v][w].push_back(u);
        s[u].insert(v),s[v].insert(u);
    }
    for(int i=1;i<=n;i++)
    {
        for(auto it:e[i])
        {
            id[i][it.first]=++tot,f[tot]=tot;
            for(int v:it.second)merge(v,tot);
        }
    }
    while(q--)
    {
        int u,v,w;
        char op;
        cin>>op;
        scanf("%d%d",&u,&v);
        if(op=='+')
        {
            scanf("%d",&w);
            s[find(u)].insert(v);
            s[find(v)].insert(u);
            if(id[u][w])merge(v,id[u][w]);
            else id[u][w]=++tot,f[tot]=tot,merge(v,tot);
            if(id[v][w])merge(u,id[v][w]);
            else id[v][w]=++tot,f[tot]=tot,merge(u,tot);
        }
        else
        {
            if(find(u)!=find(v)&&!s[find(u)].count(v))printf("No\n");
            else printf("Yes\n");
        }
    }
    return 0;
}
posted @ 2025-04-28 15:30  AvisD  阅读(23)  评论(0)    收藏  举报