AGC012 B - Splatter Painting

 問題

N個の頂点とM個の辺のグラフが与えられる。最初、頂点は全て色0で塗られている。 それぞれの辺の長さは1である。 さらに、Q個の操作が与えられる。各操作は vi, di, ciという形式で与えられる。この意味は、頂点viから距離di以内にある頂点を色ciで上書きするということ。

方針

Q個の操作をそのままの順番で実行すると、計算量がO(N2)となり間に合わない。 Q個の操作を逆順に行う事を考える。逆順にすると、その操作によって塗られた頂点は二度と上書きされない。 dp[v][d]をつくり、同じ(v, d)について再び計算をしないようにすると(メモ化)、計算量はO(Q+(N+M)*max(di))となるらしい。

#include <iostream>
#include <vector>
#include <utility>
#include <cmath>
#include <algorithm>
#include <queue>
using namespace std;
typedef long long ll;

vector<int> g[100010];
vector<int> color(100010, 0);
vector< vector<bool> > dp;

void search(int d, int v, int c) {
    if(dp[v][d]) return;
    dp[v][d] = true;
    if(color[v]==0) color[v] = c;
    if(d==0) {
        //color[v] = c; 
        return;
    }
    search(d-1, v, c);
    for(int i=0;i<g[v].size();i++) {
        search(d-1, g[v][i], c);
    }

}

int main() {
    dp = vector< vector<bool> >(100010, vector<bool>(12, false));
    ll n, m;
    cin >> n >> m;
    for(int i=0;i<m;i++) {
        int ai, bi;
        cin >> ai >> bi;
        ai--; bi--;
        g[ai].push_back(bi);
        g[bi].push_back(ai);
    }
    int Q;
    cin >> Q;
    vector<int> v(Q), dv(Q), cv(Q);
    for(int i=0;i<Q;i++) {
        cin >> v[i] >> dv[i] >> cv[i];
        v[i]--;
    }

    for(int i=Q-1;i>=0;i--) {
        search(dv[i], v[i], cv[i]);
    }

    for(int i=0;i<n;i++) {
        cout << color[i] << endl;
    }

}