AtCoder Beginner Contest 264 Solution更好的阅读体验戳此进入题面链接题面 Luogu 链接abcd 不说了[ABC264E] Blackout 2题面SolutionCode[ABC264F] Monochromatic Path题面SolutionCode[ABC264G] String Fair题面SolutionCode[ABC264Ex] Perfect Binary Tree题面SolutionCodeUPD
ZK 国有 
这些地点的标号为 
这个国家有 
现在有 
每次询问后输出有供电的城市。
没什么可说的,比较显然,把询问离线然后倒着做,用并查集维护加边即可,经典套路。
xxxxxxxxxx93123
456789
10using namespace std;11
12mt19937 rnd(random_device{}());13int rndd(int l, int r){return rnd() % (r - l + 1) + l;}14bool rnddd(int x){return rndd(1, 100) <= x;}15
16typedef unsigned int uint;17typedef unsigned long long unll;18typedef long long ll;19typedef long double ld;20
21template < typename T = int >22inline T read(void);23
24struct Edge{int s, t;}edg[510000];25int N, M, E;26int Q;27ll rans[510000];28bool del[510000];29int qs[510000];30ll ans(0);31
32class UnionFind{33private:34    int fa[510000];35    int siz[510000];36    bool light[510000];37public:38    UnionFind(void){for(int i = 1; i <= 501000; ++i)fa[i] = i;}39    void Init(void){40        for(int i = 1; i <= N; ++i)siz[i] = 1;41        for(int i = N + 1; i <= N + M; ++i)light[i] = true;42    }43    int Find(int x){return x == fa[x] ? x : fa[x] = Find(fa[x]);}44    void Merge(int s, int t){45        int rs = Find(s), rt = Find(t);46        if(rs == rt)return;47        // printf("Mergeing rs = %d, rt = %d, light is %d %d\n", rs, rt, light[rs] ? 1 : 0, light[rt] ? 1 : 0);48        if(light[rs] ^ light[rt]){49            if(!light[rs] && light[rt])swap(rs, rt);50            ans += siz[rt];51            siz[rs] += siz[rt];52            fa[rt] = rs;53        }else{54            siz[rs] += siz[rt];55            fa[rt] = rs;56        }57    }58}uf;59
60int main(){61    // freopen("test_18.txt", "r", stdin);62    // freopen("out.txt", "w", stdout);63    N = read(), M = read(), E = read();64    uf.Init();65    for(int i = 1; i <= E; ++i){66        int s = read(), t = read();67        edg[i] = Edge{s, t};68    }Q = read();69    for(int i = 1; i <= Q; ++i)del[qs[i] = read()] = true;70    for(int i = 1; i <= E; ++i)if(!del[i])uf.Merge(edg[i].s, edg[i].t);//, printf("merge : %d %d\n", edg[i].s, edg[i].t);71    for(int i = Q; i >= 1; --i){72        rans[i] = ans;73        uf.Merge(edg[qs[i]].s, edg[qs[i]].t);74    }for(int i = 1; i <= Q; ++i)printf("%lld\n", rans[i]);75    fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);76    return 0;77}78
79template < typename T >80inline T read(void){81    T ret(0);82    int flag(1);83    char c = getchar();84    while(c != '-' && !isdigit(c))c = getchar();85    if(c == '-')flag = -1, c = getchar();86    while(isdigit(c)){87        ret *= 10;88        ret += int(c - '0');89        c = getchar();90    }91    ret *= flag;92    return ret;93}给定一个 
首先不难想到每一行或一列最多进行一次反转操作,否则是无用的。发现只能向右或向下,则无后效性,故可以尝试 DP。
设 
我们设当前状态为 
对于向右走的下一步也同理可得。
初始值即为 
最终答案即为 
xxxxxxxxxx71123
45678910
11using namespace std;12
13mt19937 rnd(random_device{}());14int rndd(int l, int r){return rnd() % (r - l + 1) + l;}15bool rnddd(int x){return rndd(1, 100) <= x;}16
17typedef unsigned int uint;18typedef unsigned long long unll;19typedef long long ll;20typedef long double ld;21
22template < typename T = int >23inline T read(void);24
25int H, W;26ll R[2100], C[2100];27ll dp[2100][2100][2][2];28bitset < 2100 > G[2100];29
30int main(){31    H = read(), W = read();32    for(int i = 1; i <= H; ++i)R[i] = read();33    for(int i = 1; i <= W; ++i)C[i] = read();34    for(int i = 1; i <= H; ++i)35        for(int j = 1; j <= W; ++j){36            char c = getchar(); while(!isdigit(c))c = getchar();37            G[i][j] = c == '1' ? true : false;38        }39    memset(dp, 0x3f, sizeof dp);40    dp[1][1][0][0] = 0, dp[1][1][1][0] = R[1], dp[1][1][0][1] = C[1], dp[1][1][1][1] = R[1] + C[1];41    for(int i = 1; i <= H; ++i)42        for(int j = 1; j <= W; ++j)43            for(int x = 0; x <= 1; ++x)44                for(int y = 0; y <= 1; ++y){45                    if((G[i][j] ^ x ^ y )== (G[i + 1][j] ^ y))dp[i + 1][j][0][y] = min(dp[i + 1][j][0][y], dp[i][j][x][y]);46                    else dp[i + 1][j][1][y] = min(dp[i + 1][j][1][y], dp[i][j][x][y] + R[i + 1]);47                    if((G[i][j] ^ x ^ y) == (G[i][j + 1] ^ x))dp[i][j + 1][x][0] = min(dp[i][j + 1][x][0], dp[i][j][x][y]);48                    else dp[i][j + 1][x][1] = min(dp[i][j + 1][x][1], dp[i][j][x][y] + C[j + 1]);49                }50    ll ans(LONG_LONG_MAX);51    for(int x = 0; x <= 1; ++x)for(int y = 0; y <= 1; ++y)ans = min(ans, dp[H][W][x][y]);52    printf("%lld\n", ans);53    fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);54    return 0;55}56
57template < typename T >58inline T read(void){59    T ret(0);60    int flag(1);61    char c = getchar();62    while(c != '-' && !isdigit(c))c = getchar();63    if(c == '-')flag = -1, c = getchar();64    while(isdigit(c)){65        ret *= 10;66        ret += int(c - '0');67        c = getchar();68    }69    ret *= flag;70    return ret;71}给定 Infinity。
一个十分精妙的图论。
关键的信息在 
于是考虑如对于从 
这样将图建完之后不难发现只需要 SPFA 跑一遍单源最长路,取最大的 
于是点数为 
当然这里我们用 map 实现,手动实现一个 hash() 之后用 unorderer_map 即可去掉 map 的 
xxxxxxxxxx104123
45678910
11using namespace std;12
13mt19937 rnd(random_device{}());14int rndd(int l, int r){return rnd() % (r - l + 1) + l;}15bool rnddd(int x){return rndd(1, 100) <= x;}16
17typedef unsigned int uint;18typedef unsigned long long unll;19typedef long long ll;20typedef long double ld;21
22
23
24template < typename T = int >25inline T read(void);26
27struct Edge{28    Edge* nxt;29    int to;30    ll val;31    OPNEW;32}ed[21000];33ROPNEW(ed);34Edge* head[1100];35
36int N;37int cnt(0);38unordered_map < string, int > score;39map < pair < int, int >, int > mp;40unordered_map < int, pair < int, int > > rmp;41bitset < 1100 > inq;42int dep[1100];43ll dis[1100];44ll ans(LONG_LONG_MIN);45
46void SPFA(void){47    memset(dis, 0xc0, sizeof dis);48    queue < int > cur;49    cur.push(1); inq[1] = true; dep[1] = 1, dis[1] = 0;50    while(!cur.empty()){51        int p = cur.front(); cur.pop();52        inq[p] = false;53        for(auto i = head[p]; i; i = i->nxt){54            if(dis[p] + i->val > dis[SON]){55                dis[SON] = dis[p] + i->val;56                ans = max(ans, dis[SON]);57                dep[SON] = dep[p] + 1;58                if(dep[SON] > 26 * 26 + 26 + 1)printf("Infinity\n"), exit(0);59                if(!inq[SON])cur.push(SON), inq[SON] = true;60            }61        }62    }63}64
65int main(){66    N = read();67    for(int i = 1; i <= N; ++i){68        string S; cin >> S;69        score.insert({S, read()});70    }mp.insert({{0, 0}, ++cnt}), rmp.insert({cnt, {0, 0}});71    for(int i = 'a'; i <= 'z'; ++i)mp.insert({{0, i}, ++cnt}), rmp.insert({cnt, {0, i}});72    for(int i = 'a'; i <= 'z'; ++i)for(int j = 'a'; j <= 'z'; ++j)73        mp.insert({{i, j}, ++cnt}), rmp.insert({cnt, {i, j}});74    for(int i = 1; i <= cnt; ++i)for(int j = 'a'; j <= 'z'; ++j){75        ll tot(0); string S;76        if(rmp[i].first)S += (char)rmp[i].first;77        if(rmp[i].second)S += (char)rmp[i].second;78        S += j; tot += score[S];79        while(!S.empty()){80            S.erase(S.begin());81            tot += score[S];82        }83        head[i] = new Edge{head[i], mp[{rmp[i].second, j}], tot};84    }SPFA();85    printf("%lld\n", ans);86    fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);87    return 0;88}89
90template < typename T >91inline T read(void){92    T ret(0);93    int flag(1);94    char c = getchar();95    while(c != '-' && !isdigit(c))c = getchar();96    if(c == '-')flag = -1, c = getchar();97    while(isdigit(c)){98        ret *= 10;99        ret += int(c - '0');100        c = getchar();101    }102    ret *= flag;103    return ret;104}存在一棵以 
首先一个比较重要的性质就是 
不难想到 DP,令 
朴素的转移十分显然,即在其儿子里找到两个层高为 
考虑到我们每次询问都是增加一个节点,如此的转移方式复杂度显然是不正确的,考虑优化。不难想到这个式子可以转化为从和平方里去除平方和,即:
于是这个东西就可以支持 
最终的答案即为 
所以每次修改都是 
xxxxxxxxxx110123
45678910
11using namespace std;12
13mt19937 rnd(random_device{}());14int rndd(int l, int r){return rnd() % (r - l + 1) + l;}15bool rnddd(int x){return rndd(1, 100) <= x;}16
17typedef unsigned int uint;18typedef unsigned long long unll;19typedef long long ll;20typedef long double ld;21
2223
24template < typename T = int >25inline T read(void);26
27struct Edge{28    Edge* nxt;29    int to;30    OPNEW;31}ed[610000];32ROPNEW(ed);33Edge* head[310000];34
35ll qpow(ll a, ll b){36    ll ret(1), mul(a);37    while(b){38        if(b & 1)ret = ret * mul % MOD;39        b >>= 1;40        mul = mul * mul % MOD;41    }return ret;42}43
44int N;45int mxdep;46int inv2;47int dep[310000];48int fa[310000];49ll ans(0);50ll sum[310000][21], sum2[310000][21];51
52ll DP(int p, int i){53    if(i == 1)return 1;54    return ((sum[p][i] * sum[p][i] % MOD - sum2[p][i]) % MOD + MOD) % MOD * inv2 % MOD;55}56void dfs(int p = 1, int fa = 0){57    dep[p] = dep[fa] + 1;58    for(auto i = head[p]; i; i = i->nxt)59        if(SON != fa)dfs(SON, p);60}61
62int main(){63    // freopen("in.txt", "r", stdin);64    // freopen("out.txt", "w", stdout);65    inv2 = qpow(2, MOD - 2);66    N = read();67    if(N == 1)printf("1\n"), exit(0);68    mxdep = (int)log2(N);69    for(int i = 2; i <= N; ++i){70        fa[i] = read();71        head[i] = new Edge{head[i], fa[i]};72        head[fa[i]] = new Edge{head[fa[i]], i};73    }dfs();74    for(int cp = 1; cp <= N; ++cp){75        if(dep[cp] <= mxdep){76            sum[cp][1] = sum2[cp][1] = 1;77            ll cnt(1), cur(cp), lst(-1), lstDP(0);78            while(cur != 1){79                lst = cur;80                cur = fa[cur], ++cnt;81                ll tmp = DP(cur, cnt);82                (((sum[cur][cnt] -= lstDP) %= MOD) += MOD) %= MOD;83                (((sum2[cur][cnt] -= lstDP * lstDP % MOD) %= MOD) += MOD) %= MOD;84                lstDP = tmp;85                (sum[cur][cnt] += DP(lst, cnt - 1)) %= MOD;86                (sum2[cur][cnt] += DP(lst, cnt - 1) * DP(lst, cnt - 1) % MOD) %= MOD;87            }88        }ans = 0;89        for(int i = 1; i <= mxdep; ++i)(ans += DP(1, i)) %= MOD;90        printf("%lld\n", ans);91    }92    fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);93    return 0;94}95
96template < typename T >97inline T read(void){98    T ret(0);99    int flag(1);100    char c = getchar();101    while(c != '-' && !isdigit(c))c = getchar();102    if(c == '-')flag = -1, c = getchar();103    while(isdigit(c)){104        ret *= 10;105        ret += int(c - '0');106        c = getchar();107    }108    ret *= flag;109    return ret;110}update-2023_01_03 初稿