\(\frak{Description}\)

给定一个 \(n\) 个点,\(m\) 条边的连通无向图,图有边权,每个点有一个颜色。有 \(q\) 次操作,每次操作可改变某一点颜色。
每次操作后求图中不同颜色点的最短距离。
保证图中点颜色至少存在两种,图颜色的种数为 \(c\).

\(c,q,n\le 2\cdot 10^5,m\le 3\cdot 10^5\).

\(\frak Solution\)

谁能知道我连根号分治都妹想到呢,还以为不能做……而且这题的数据竟然还能跑过,就离谱。

首先这题有两个结论:

  • 最短距离一定是一条边;
  • 这条边一定在原图的最小生成树上。考虑证明,一个感性的猜测是会不会发生连通块内的树边都不可用,而非树边可以使用的情况。事实上,"相等" 是有传递性的,也就是说我们模拟 \(\rm kruskal\) 求最小生成树的过程,如果树边都不可用相当于这个块的颜色全部相同,此时非树边显然也不可以使用。

后来想了想,当时根号分治没有想出来的原因是对于可修改的取 \(\min\) 查询的套路没有摸清:为啥不用 \(\rm multiset\) 呢?才一个 \(\log\) 呢!由于上文已经将边数缩减到 \(n\) 级别,所以根号分治变成了根号下 \(n\). 对于度数 \(<\sqrt n\) 的点,就直接枚举,更新答案 \(\rm multiset\)(全局)即可;对于度数 \(\ge \sqrt n\) 的点,开一棵线段树(值域为颜色)维护区间最小边权(叶子节点还是一个 \(\rm multiset\)),其实就是无法枚举邻接点,所以用 \(<\sqrt n\) 的点来更新。所以总共是 \(\mathcal O(n\sqrt n\log n)\) 的。

接下来可能是一个 \(\rm trick\) 吧:考虑我们已经将可选边的集合缩成了树的形式,就可以利用这个结构来思考。对于点 \(u\)\(c\)\(\rm multiset\)(这里只是为了叙述方便,实际上只用开至多 \(\sum_{v\in \text{son}(u)}1\) 个), 将每个 \(\rm multiset\) 中的最小边权扔进一个答案 \(\rm multiset\)(全局),然后瞎 \(\rm jb\) 判断一下就行了。所以总共是 \(\mathcal O(n\log n)\) 的。

\(\frak Code\)

另外还从别人那里抄来一个优先队列延迟模拟 \(\rm multiset\) 的,具体就看代码辣~

#include <cstdio>
#define print(x,y) write(x),putchar(y)

template <class T>
inline T read(const T sample) {
	T x=0; char s; bool f=0;
	while((s=getchar())>'9' || s<'0')
		f |= (s=='-');
	while(s>='0' && s<='9')
		x = (x<<1)+(x<<3)+(s^48),
		s = getchar();
	return f?-x:x;
}

template <class T>
inline void write(T x) {
	static int writ[50],tp=0;
	if(x<0) putchar('-'),x=-x;
	do writ[++tp] = x-x/10*10, x /= 10; while(x);
	while(tp) putchar(writ[tp--]^48);
}

#include <queue>
#include <algorithm>
#include <unordered_map>
using namespace std;

const int maxn = 2e5+5;
const int maxm = 3e5+5;

int n,m,q,cnt,W[maxn],col[maxn];
int head[maxn],f[maxn],fa[maxn];
struct Edges {
    int u,v,w;

    bool operator < (const Edges& t) const {
        return w<t.w;
    }
} E[maxm];
struct edge {
    int nxt,to,w;
} e[maxn<<1];
struct heap {
    priority_queue < int, vector <int>, greater <int> > q,del;

    inline void upd() {
        while(!del.empty() && q.top()==del.top())
            q.pop(), del.pop();
    }
    inline int top() { return upd(),q.top(); }
    inline int size() { return upd(),q.size()-del.size(); }
    inline void push(int x) { q.push(x); }
    inline void pop(int x) { del.push(x); }
} ans;
unordered_map <int,heap> t[maxn];

void addEdge(int u,int v,int w) {
    e[++ cnt].to=v, e[cnt].nxt=head[u];
    e[cnt].w=w, head[u]=cnt;
	e[++ cnt].to=u, e[cnt].nxt=head[v];
	e[cnt].w=w, head[v]=cnt;
}

int Find(int x) {
    return x==f[x]?x:f[x]=Find(f[x]);
}

void Kruskal() {
    for(int i=1;i<=n;++i) f[i]=i;
    sort(E+1,E+m+1);
    for(int i=1;i<=m;++i) {
        int u=E[i].u,v=E[i].v;
        if(Find(u)^Find(v)) {
            f[Find(u)] = Find(v);
            addEdge(u,v,E[i].w);
        }
    }
}

void dfs(int u,int die) {
    for(int i=head[u]; i; i=e[i].nxt) {
        int v=e[i].to;
        if(v==die) continue;
        t[u][col[v]].push(e[i].w);
        fa[v]=u; W[v]=e[i].w;
        dfs(v,u);
    }
    for(auto& [c,Q]:t[u])
        if(c^col[u]) ans.push(Q.top());
}

void change(int x,int y) {
    if(col[x]==y) return;
    if(fa[x]) {
        heap &h = t[fa[x]][col[x]];
        if(col[x]^col[fa[x]]) ans.pop(h.top());
        h.pop(W[x]);
        if(!h.size()) t[fa[x]].erase(col[x]);
        else if(col[x]^col[fa[x]]) ans.push(h.top());
        heap &H = t[fa[x]][y];
        if(H.size() && y!=col[fa[x]]) ans.pop(H.top());
        H.push(W[x]);
        if(y^col[fa[x]]) ans.push(H.top());
    }
    if(t[x].count(col[x])) ans.push(t[x][col[x]].top());
    if(t[x].count(y)) ans.pop(t[x][y].top());
    col[x]=y;
}

int main() {
    freopen("color.in","r",stdin);
    freopen("color.out","w",stdout);
    n=read(9), m=read(9);
    read(9), q=read(9);
    for(int i=1;i<=m;++i)
        E[i].u=read(9), E[i].v=read(9),
        E[i].w=read(9);
    for(int i=1;i<=n;++i) col[i]=read(9);
    Kruskal(); dfs(1,0);
    while(q --) {
        int x=read(9),y=read(9);
        change(x,y);
        print(ans.top(),'\n');
    }
    return 0;
}
posted on 2020-03-19 11:06  Oxide  阅读(974)  评论(1编辑  收藏  举报