zoukankan      html  css  js  c++  java
  • P3665 [USACO17OPEN]Switch Grass

    题目描述

      N个点M条边的无向图,每个点有一个初始颜色,每次改变一个点的颜色,求改变后整张图上颜色不同的点之间的距离最小值。

    思路

    考虑整张图的距离最小值一定是一条边,而不可能是一条路径,那么显然这条边一定在MST上,于是我们考虑怎样维护这棵MST。

    • 首先我们用kruskal建出MST,然后转化为有根树,把边权下放为点权,只维护每个点和它儿子的信息。
    • 我们对每个节点所有儿子的颜色开一个multiset,维护每个点的儿子中每种颜色对应的最小边权(此时下放为点权),为了节省空间我们用map映射把颜色那维去掉,即$CLS_{u,col}}
    • 接着我们再对每个点开一个multiset维护每个点儿子中所有颜色对应的最小边权的最小值(就是上一个multiset维护的东西的最小值)。即$best[u]=min{CLS_{u,c} }_{C in all colors }$
    • 最后我们对全局开一棵线段树,维护每个点的best中和它颜色不同的点的最小值,便于修改和查询。
    • 于是每个点的答案不是$*best.begin()就是*(best.begin()+1)$,如果儿子中点权最小的儿子和父亲颜色相同,那么显然是次小的(或者无解)。
    • 怎样修改,考虑我们修改u时,先把$u$从父亲节点的信息中删去,再加回来。这里的方法是:先把$best$中对应的$col[u]$的信息删掉,然后把当前点所在的$cls[f[u]][col]$中找到并删去当前点,重新排序后再加入$best$中;接着把u的信息加入到$cls[f[u]][B]$(B为修改后颜色)中,同样先删去$best$中B的信息删掉,然后把u的信息加入$cls[f[u][B]$中,重新排序后再加入$best$中。
    #include<bits/stdc++.h>
    #define I inline
    #define fi first
    #define se second
    #define mp make_pair
    #define ls (now<<1)
    #define rs (now<<1|1)
    #define smid (l+r>>1)
    using namespace std;
    typedef map<int,multiset<int> >::iterator itcls;
    //神仙typedef,这里是map的指针,it->fi是前面的集合,it->se是后面映射的集合
    typedef set<pair<int,int> >::iterator itset;//it是一个pair型的东西
    const int N=2000010;
    const int inf=2147483647;
    I int read()
    {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    
    struct EDGE
    {
        int u,v,w;
    }e[N];
    struct node
    {
        int to,nxt,w;
    }g[N<<1];
    int head[N],cnt;
    int n,m,k,q;
    int col[N],w[N],f[N];
    
    int mi[N<<2];
    I void pushup(int now){mi[now]=min(mi[ls],mi[rs]);}
    
    I void bt(int now,int l,int r)
    {
        mi[now]=inf;
        if(l==r)return;
        bt(ls,l,smid);bt(rs,smid+1,r);
        pushup(now);
    }
    
    I void modify(int now,int l,int r,int pos,int val)
    {
        if(l==r){mi[now]=val;return;}
        if(pos<=smid)modify(ls,l,smid,pos,val);
        else modify(rs,smid+1,r,pos,val);
        pushup(now);
    }
    
    I bool cmp(EDGE a,EDGE b){return a.w<b.w;}
    
    I void add(int u,int v,int w)
    {
        g[++cnt].nxt=head[u];
        g[cnt].to=v;g[cnt].w=w;
        head[u]=cnt;
    }
    
    struct DSU
    {
        int f[N];
        I void init(int x){for(int i=1;i<=x;i++)f[i]=i;}
        I int getf(int x){return x==f[x]?x:f[x]=getf(f[x]);}
    }dsu;
    
    I void kruskal()
    {
        sort(e+1,e+1+m,cmp);
        int tot=0;cnt=0;
        dsu.init(n);
        for(int i=1;i<=m;i++)
        {
            int u=e[i].u,v=e[i].v,w=e[i].w;
            if(dsu.getf(u)!=dsu.getf(v))
            {
                dsu.f[dsu.getf(u)]=dsu.getf(v);
                tot++;add(u,v,w);add(v,u,w);
                if(tot==n-1)return;
            }
        }
    }
    
    map<int,multiset<int> >cls[N];
    multiset<pair<int,int> >best[N];
    
    I void dfs(int u,int fa)
    {
        f[u]=fa;
        for(int i=head[u];i;i=g[i].nxt)
        {
            int v=g[i].to;
            if(v==fa)continue;
            w[v]=g[i].w;cls[u][col[v]].insert(w[v]);
            dfs(v,u);
        }
        for(itcls it=cls[u].begin();it!=cls[u].end();it++)
        best[u].insert(mp(*((it->se).begin()),it->fi));
        //真·STL,(it维护的是map的指针,it->se是映射的multiset,it->fi是颜色
        if(best[u].empty())return;
    
        itset it=best[u].begin();
        if((it->se)!=col[u])modify(1,1,n,u,it->fi);
        else
        {
            it++;if(it==best[u].end())modify(1,1,n,u,inf);
            else modify(1,1,n,u,it->fi);
        }
    }
    
    int main()
    {
        n=read();m=read();k=read();q=read();
        for(int i=1;i<=m;i++)
        {
            int x=read(),y=read(),z=read();
            e[++cnt]=(EDGE){x,y,z};
        }
        for(int i=1;i<=n;i++)col[i]=read();
        kruskal();bt(1,1,n);dfs(1,0);
        while(q--)
        {
            int u=read(),c2=read();
            if(f[u])
            {
                int c1=col[u];
                best[f[u]].erase(best[f[u]].find(mp(*cls[f[u]][c1].begin(),c1)));
                cls[f[u]][c1].erase(cls[f[u]][c1].find(w[u]));
                if(cls[f[u]][c1].empty())cls[f[u]][c1].insert(inf);
                best[f[u]].insert(mp(*cls[f[u]][c1].begin(),c1));
    
                if(!cls[f[u]][c2].empty())
                best[f[u]].erase(best[f[u]].find(mp(*cls[f[u]][c2].begin(),c2)));
                cls[f[u]][c2].insert(w[u]);
                best[f[u]].insert(mp(*cls[f[u]][c2].begin(),c2));
                itset it=best[f[u]].begin();
                if((it->se)!=col[f[u]])modify(1,1,n,f[u],it->fi);
                else
                {
                    it++;if(it==best[f[u]].end())modify(1,1,n,f[u],inf);
                    else modify(1,1,n,f[u],it->fi);
                }
            }
            if(!best[u].empty())
            {
                itset it=best[u].begin();
                if((it->se)!=c2)modify(1,1,n,u,it->fi);
                else
                {
                    it++;if(it==best[u].end())modify(1,1,n,u,inf);
                    else modify(1,1,n,u,it->fi);
                }
            }
            col[u]=c2;
            printf("%d
    ",mi[1]);
        }
    }
  • 相关阅读:
    stack2
    xctf 实时数据监测
    note-service2
    stack pivot学习
    sctf_2019_easy_heap 利用off-by-null构造出double free来向任一地址写入(经典)
    ciscn_2019_s_1 unlink或者of-by-null
    starctf_2019_babyshell 绕过循环检测注入shellcode
    sublime 安装package control
    windows上安装nodejs,升级npm,安装webpack指南
    mysql 常见语句
  • 原文地址:https://www.cnblogs.com/THRANDUil/p/11823874.html
Copyright © 2011-2022 走看看