码迷,mamicode.com
首页 > 其他好文 > 详细

P3665 [USACO17OPEN]Switch Grass

时间:2019-11-08 23:52:07      阅读:102      评论:0      收藏:0      [点我收藏+]

标签:父亲节   push   信息   ==   怎样   mod   颜色   get   一个   

题目描述

  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\n",mi[1]);
    }
}

 

 

 

 

 

 

 

P3665 [USACO17OPEN]Switch Grass

标签:父亲节   push   信息   ==   怎样   mod   颜色   get   一个   

原文地址:https://www.cnblogs.com/THRANDUil/p/11823874.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!