电子科技大学2022暑假前集训 图论专题

题解

A

\(n-1\) 次最大流,每次以 \(1\) 为源点,\(i\) 为汇点。然后就过了((PS:此题实际上是 Stoer-Wagner 模板题)

B

首先肯定是跑最小生成树。那么每次合并两个集合时,考虑启发式合并,将小集合中每个点取出,然后在大集合中计算与取出的点点权之差小于 \(L\) 的点的数目,乘上边权加到答案里。考虑手写平衡树或者 pb_ds 维护集合中点权在一个区间内的点的数目。注意特判 \(L=0\) 的情况,如果出现两个点点权相同会被计算两次。

C

显然对角线如果和管道方向相同就连 \(0\) 边,不同就连 \(1\) 边。从一个结点开始 BFS,每到达一个未访问过结点,利用 DFS 将距离为 \(0\) 的连通块全部标记为 vis 并入队。

D

考虑矩阵快速幂,每转移到 \(d_i\) 次将一些边加入邻接矩阵。最后 Bitset 优化布尔矩阵快速幂。

E

点双缩点,将点双和割点都看作新图中的点来建图。注意如果询问的点对中某一个为割点,则必须将这一点看作对应新图中的割点形成的点。

F

差分约束裸题。由 \(v\)\(u\) 连一条权值为 \(w\) 的边,然后跑 SPFA,若有负环则说明无解。

G

单独计算每一对 \(A_i\)\(B_j\) 匹配之后得到的期望得分,问题转化为最大权匹配,利用 KM 算法解决。

H

奇数连通块必然可拆成一个奇数连通块和一个偶数连通块,奇数连通块再拆,从而最后一定拆出一个孤立点,反过来一个奇数连通块要且只要拆掉一个点。考虑拆掉哪个点。如果一个点拆掉之后形成的所有联通块为偶数,则可拆,若存在奇数,则必须再拆点,使得拆点数量多于一个,不符合结论。而只有割点会产生多个连通块,因此 DCC 缩点之后在树上跑 DP,求出与一个割点相连的连通块是否存在奇数连通块。最后按点权从小到大的顺序枚举点,若该点可删且所在连通块为奇数连通块,则删除该点并将连通块标记为偶数连通块。

I

2-SAT 裸题。将一个点拆成两个点 \(u_0\) \(u_1\),令 \(u\)\(v\) 连边表示若 \(u\)\(v\)。那么,例如一组约束条件为 \(u\) \(0\) \(v\) \(1\),则 \(u_1\)\(v_1\) 连边,\(v_0\)\(u_0\) 连边。然后跑强连通分量,如果 \(u_0\)\(u_1\) 在同一个强连通分量中,说明 \(u\) 同时为 \(0\)\(1\),自相矛盾,因此无解。否则,若所有点都满足拆成的两点不在同一强连通分量中,则说明是有解的。

J

割点、割边、点双个数:跑一遍 Tarjan。

点双包含的边数的最大值:观察到数据范围小,因此我们可以暴力枚举所有边,然后将每条边的两个端点所属的点双取交集,交集必然只有一个点双,该点双就是该边所属的点双。

K

给出数据是一棵树。先钦定一点为根跑 DFS,跑出每点的深度。对于每个询问 \(u\)\(v\) 求 LCA,则答案就是 \(dep_u+dep_v-dep_{lca}\)

L

在所有最小生成树中,同一边权的边个数一定相同,且形成的连通块也相同。基于这一点,我们先跑出一个最小生成树,然后枚举每一边权的边。对于除该边权以外的边,若它在最小生成树上,则将该边连接的两点缩点。最后利用矩阵树定理即可计算出某一边权的边对应的生成树数量。将所有边权的生成树数量相乘即为答案。

M

\(k\) 短路模板题。

在反向图上,以 \(t\) 为根建立最短路径树。则如果我们钦定一条非最短路径边 \((u,v)\) 必须被使用,则路径长度增加 \(dis_v+w-dis_u\)

于是我们设计一个状态四元组 \(\{u,v,w,e\}\),其中 \(u\) 表示倒数第二条钦定边的终点,\(v\) 表示倒数第一条钦定边的终点,\(w\) 表示该状态方案的路径长度,\(e\) 表示最后一条边。那么从该状态扩展,可以扩展到两个状态:

  • \(e\) 替换为一条另一条以 \(u\) 的祖先为起点且恰劣于 \(e\) 的边,同时 \(v\) 会发生改变;

  • 增加一条以 \(v\) 的祖先为起点的边,同时 \(u\) 变为 \(v\)\(v\)\(e\) 变为新值。

将状态放入以 \(w\) 为关键字的优先队列,每次取出队头进行扩展,扩展 \(k\) 次就得到了 \(k\) 短路。

N

最小直径生成树模板题。

定义图的绝对中心为到所有点的最短距离的最大值最小的位置,这个位置可能在点上,也可能在一条边上。

那么,首先用 Floyd 求出两两点之间的最短路。设 \(d(i,j)\) 表示 \(i\)\(j\) 之间的最短路,\(rk(i,k)\) 表示所有点中到 \(i\) 距离第 \(k\) 远的点。

如果绝对中心在点上,则答案就是 \(\min_i\{d(i,rk(i,n))×2\}\)

如果绝对中心在一条边 \((u,v)\) 上,我们不妨 “枚举” \((u,v)\) 上的每一个点 \(c\),设 \(c\)\(u\) 的距离为 \(x\),则 \(c\)\(v\) 的距离为 \(w-x\)。那么 \(c\) 到某点 \(i\) 的距离就是 \(\min_x\{d(u,i)+x,d(v,i)+w-x\}\)。随着 \(c\)\(u\) 移动到 \(v\)\(c\) 到一点 \(i\) 的距离将会先上升后下降,形成一个单峰折线。对于所有 \(i\) 对应折线的上壳,其最低点对应的 \(c\) 就是该边上绝对中心的可能位置。找出该位置更新答案即可。

O

最短路裸题。跑一遍 Dijkstra 即可。

P

从左上角生成一颗到所有特殊格的最短路径生成树,钦定回路包含该生成树即可。

Q

当选择一个点加入生成树时,在线段树上用该点更新到达不在生成树中的点的最短距离。

更具体地,开两颗线段树,一颗维护从某个生成树上的点 \(u\) 向左走到达每个点 \(v\) \((v<u)\) 的最短距离。那么显然 \(dist_{u,v}=(A_u+uD)+(A_v-vD)\)。线段树上维护两个值,一个是终点 \(v\) 的权值 \(A_v-vD\),一个是起点 \(u\) 的权值 \(A_u+uD\)。由于在起点中我们只会选择权值最小的那个,而起点权值是对一个前缀区间取 \(\min\),这使得我们最多会产生 \(n\) 个区间,使得这些区间两两起点权值不同。对于每个这样的区间,取其中终点权值最小的点即可。

另一颗线段树同理。

R

最小树形图裸题,使用朱刘算法解决。具体流程是,每次对于每一点都选择到达该点的边中权值最小的边,然后将图中的环缩点,再不断执行这一流程。

S

一般图最大匹配裸题,使用带花树算法解决。

带花树算法:DFS 时顺便黑白染色,于是第二次访问某节点时可以知道所成的环是奇环还是偶环。对于奇环,必然可以让其中任意一个点向外匹配,其他形成完美匹配,于是缩点即可。不停缩点直到不存在奇环,然后跑普通二分图匹配。

T

DAG 上的最少路径覆盖裸题,等价于二分图最大匹配问题。

具体而言,每当我们选中一条边,我们的路径条数就会减 1。因此我们要最大化选中的路径条数。如果把从 \(u\)\(v\) 的边看作匹配 \((u,v)\),那么就转化为二分图最大匹配问题。

代码

A

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int N = 301, M = 1001;

int n, m, s, t, head[N], nxt[M << 1], to[M << 1], c[M << 1], tmp[M << 1], eid = 2;
inline void addedge(int u, int v, int w){
	to[eid] = v;
	c[eid] = w;
	nxt[eid] = head[u];
	head[u] = eid++;
}

int d[N], q[N], l, r;

long long dfs(int i, long long f = 0x7fffffffffffffff){
	if(i == t) return f;
	long long ans = 0;
	for(int e = head[i]; f && e; e = nxt[e]) if(d[to[e]] > d[i] && c[e]){
		int ret = dfs(to[e], min(f, (long long) c[e]));
		f -= ret;
		c[e] -= ret;
		c[e ^ 1] += ret;
		ans += ret;
	}
	if(!ans) d[i] = 0;
	return ans;
}

long long solve(){
    memcpy(c, tmp, sizeof(tmp));
    long long ans = 0;
    while(true){
    	memset(d + 1, 0, sizeof(int) * n);
    	d[s] = 1;
    	l = r = 0;
    	q[r++] = s;
    	while(l != r){
    		int i = q[l++];
    		for(int e = head[i]; e; e = nxt[e]) if(c[e] && !d[to[e]]){
    			d[to[e]] = d[i] + 1;
    			q[r++] = to[e];
    		}
    	}
    	if(!d[t]) break;
    	ans += dfs(s);
    }
    return ans;
}

int u, v, w;
long long ans = 0x7fffffffffffffff;

int main(){
	scanf("%d%d", &n, &m);
    s = 1;
    while(m--){
		scanf("%d%d", &u, &v);
		addedge(u, v, 1);
		addedge(v, u, 1);
	}
    memcpy(tmp, c, sizeof(c));
    for (t = 2; t <= n; t++)
        ans = min(ans, solve());
    printf("%lld", ans);
    return 0;
}

B

#include <cstdio>
#include <algorithm>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace std;
using namespace __gnu_pbds;
const int N = 2e5 + 1, M = 5e5 + 1;

struct node{
    int c, id;
    node(int _c, int _id) : c(_c), id(_id){}
    bool operator<(const node &b) const{
        return c != b.c ? c > b.c : id > b.id;
    }
};

tree<node, null_type, less<node>, rb_tree_tag, tree_order_statistics_node_update> tr[N];

int n, m, k, c, fa[N];
int find(int x){
    return x == fa[x] ? x : fa[x] = find(fa[x]);
}

struct edge{
    int u, v, w;
    edge(){}
    edge(int _u, int _v, int _w) : u(_u), v(_v), w(_w){}
    bool operator<(const edge &b) const{
        return w < b.w;
    }
}e[M];

long long ans;

int main(){
    scanf("%d%d%d", &n, &m, &k);
    for (int i = 1; i <= n; i++){
        fa[i] = i;
        scanf("%d", &c);
        tr[i].insert(node(c, i));
    }
    for (int i = 1; i <= m; i++)
        scanf("%d%d%d", &e[i].u, &e[i].v, &e[i].w);
    sort(e + 1, e + 1 + m);
    for (int i = 1; i <= m; i++){
        int u = find(e[i].u), v = find(e[i].v);
        if(u != v){
            if(tr[u].size() < tr[v].size())
                swap(u, v);
            if(k)
                for(auto nd : tr[v])
                    ans += 1ll * e[i].w * (tr[u].order_of_key(node(nd.c + k, 0)) + tr[u].size() - tr[u].order_of_key(node(nd.c - k, n + 1)));
            else
                ans += 1ll * e[i].w * tr[v].size() * tr[u].size();
            for(auto nd : tr[v])
                tr[u].insert(nd);
            fa[v] = u;
        }
    }
    printf("%lld", ans);
    return 0;
}

C

#include <cstdio>
#include <utility>
#include <queue>
#include <cstring>
using namespace std;
const int N = 502, X[4] = {1, 1, -1, -1}, Y[4] = {1, -1, -1, 1}, PX[4] = {1, 1, 0, 0}, PY[4] = {1, 0, 0, 1};
typedef pair<int, int> duo;

int n, m;
int dist[N][N];
char s[N][N];

bool legal(int x, int y){
    return x >= 0 && y >= 0 && x <= n && y <= m;
}

queue<duo> q;

void dfs(int x, int y){
    q.push(duo(x, y));
    for (int i = 0; i < 4; i++){
        int nx = x + X[i];
        int ny = y + Y[i];
        if(legal(nx, ny) && dist[nx][ny] == -1 && (s[x + PX[i]][y + PY[i]] == '/') == (i & 1)){
            dist[nx][ny] = dist[x][y];
            dfs(nx, ny);
        }
    }
}

int main(){
    memset(dist, -1, sizeof(dist));
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++)
        scanf("%s", s[i] + 1);
    dist[0][0] = 0;
    dfs(0, 0);
    while(!q.empty()){
        int x = q.front().first;
        int y = q.front().second;
        q.pop();
        for (int i = 0; i < 4; i++){
            int nx = x + X[i];
            int ny = y + Y[i];
            if(legal(nx, ny) && dist[nx][ny] == -1 && (s[x + PX[i]][y + PY[i]] == '/') != (i & 1)){
                dist[nx][ny] = dist[x][y] + 1;
                dfs(nx, ny);
            }
        }
    }
    if(dist[n][m] == -1)
        puts("NO SOLUTION");
    else
        printf("%d", dist[n][m]);
    return 0;
}

D

#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
#include <bitset>
using namespace std;
const int N = 181;

int n, m, c, u, v, w, d[N], lv[N][N], dist[N];
bitset<N> vec, tmpvec, trans[N], base[N], res[N], tmp[N], flip[N];

void matmul(bitset<N> a[N], bitset<N> b[N]){
    for (int i = 1; i <= n; i++)
        tmp[i].reset();
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++)
            flip[i][j] = b[j][i];
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= n; j++)
                tmp[i][j] = (a[i] & flip[j]).any();
    for (int i = 1; i <= n; i++)
        a[i] = tmp[i];
}

void fpow(bitset<N> res[N], bitset<N> base[N], int t){
    if(!t){
        for (int i = 1; i <= n; i++)
            res[i][i] = 1;
        return;
    }
    while(t){
        if(t & 1)
            matmul(res, base);
        matmul(base, base);
        t >>= 1;
    }
}

int ans = 0x7fffffff;
queue<int> q;

int main(){
    memset(lv, 0x3f, sizeof(lv));
    scanf("%d%d%d", &n, &m, &c);
    while(m--){
        scanf("%d%d%d", &u, &v, &w);
        lv[u][v] = min(lv[u][v], w);
    }
    vec[1] = 1;
    for (int i = 1; i <= c; i++){
        scanf("%d", &d[i]);
        for (int i = 1; i <= n; i++){
            res[i].reset();
            res[i][i] = 1;
            base[i] = trans[i];
        }
        fpow(res, base, d[i] - d[i - 1]);
        tmpvec.reset();
        for (int j = 1; j <= n; j++)
            for (int k = 1; k <= n; k++)
                tmpvec[j] = tmpvec[j] | (vec[k] & res[k][j]);
        vec = tmpvec;
        for (int j = 1; j <= n; j++)
            for (int k = 1; k <= n; k++)
                if (lv[j][k] == i)
                    trans[j][k] = 1;
        for (int i = 1; i <= n; i++){
            if(vec[i]){
                dist[i] = 0;
                q.push(i);
            }else
                dist[i] = 0x3f3f3f3f;
        }
        while(!q.empty()){
            int i = q.front();
            q.pop();
            for (int j = 1; j <= n; j++)
                if(trans[i][j] && dist[j] > dist[i] + 1){
                    dist[j] = dist[i] + 1;
                    q.push(j);
                }
        }
        ans = min(ans, d[i] + dist[n]);
    }
    if(ans >= 0x3f3f3f3f)
        puts("Impossible");
    else
        printf("%d", ans);
    return 0;
}

E

#include <cstdio>
#include <vector>
#include <iostream>
#include <cstring>
using namespace std;
const int N = 1e5 + 1, L = 20;

int n, m, q, u, v, w[N];
vector<int> g[N];

int fa[N], dfn[N], low[N], idx, stk[N], top;
int find(int x){
    return fa[x] == x ? x : fa[x] = find(fa[x]);
}
bool cut[N];
vector<int> dcc[N], belong[N];
int dcccnt;
void tarjan(int u){
    if(u == 1 && g[u].empty()){
        dcc[++dcccnt].push_back(1);
        return;
    }
    dfn[u] = low[u] = ++idx;
    stk[++top] = u;
    int cnt = 0;
    for(auto v : g[u]){
        if(!dfn[v]){
            cnt++;
            tarjan(v);
            low[u] = min(low[u], low[v]);
            if(dfn[u] <= low[v]){
                dcccnt++;
                if(u != 1 || cnt > 1)
                    cut[u] = true;
                int x;
                do{
                    x = stk[top--];
                    dcc[dcccnt].push_back(x);
                    belong[x].push_back(dcccnt);
                } while (x != v);
                dcc[dcccnt].push_back(u);
                belong[u].push_back(dcccnt);
            }
        }
        else low[u] = min(low[u], dfn[v]);
    }
}

int dccans[N], ans[N];
bool vis[N];
bool visdcc[N];
void dfs(int u){
    vector<int> vec;
    for(auto id : belong[u]) if(!visdcc[id]){
        for(auto v : dcc[id]) if(!vis[v]){
            vis[v] = true;
            ans[v] = min(ans[u], dccans[id]);
            vec.push_back(v);
        }
    }
    while(!vec.empty()){
        dfs(vec.back());
        vec.pop_back();
    }
}

int main(){
    memset(dccans, 0x7f, sizeof(ans));
    scanf("%d%d%d", &n, &m, &q);
    for (int i = 1; i <= n; i++)
        fa[i] = i;
    while (m--){
        scanf("%d%d", &u, &v);
        u = -u, v = -v;
        g[u].push_back(v);
        g[v].push_back(u);
    }
    for (int i = 1; i <= n; i++)
        scanf("%d", &w[i]);
    tarjan(1);
    for (int i = 1; i <= dcccnt; i++){
        for(auto x : dcc[i])
            dccans[i] = min(dccans[i], w[x]);
    }
    vis[1] = true;
    ans[1] = w[1];
    for(auto id : belong[1]){
        visdcc[id] = true;
        for(auto x : dcc[id]) if(x != 1){
            ans[x] = dccans[id];
            vis[x] = true;
        }
    }
    for(auto id : belong[1])
        for(auto x : dcc[id])
            dfs(x);
    ans[1] = w[1];
    dfs(1);
    while(q--){
        scanf("%d", &u);
        printf("%d\n", ans[u]);
    }
    return 0;
}

F

#include <cstdio>
#include <queue>
#include <cstring>
using namespace std;
const int N = 5e3 + 1;

int n, m, u, v, w, head[N], nxt[N], val[N], to[N], eid = 1;
void addedge(int u, int v, int w){
    to[eid] = v;
    val[eid] = w;
    nxt[eid] = head[u];
    head[u] = eid++;
}

int cnt[N];
long long dist[N];
queue<int> q;

int main(){
    scanf("%d%d", &n, &m);
    while(m--){
        scanf("%d%d%d", &u, &v, &w);
        addedge(v, u, w);
    }
    bool ans = true;
    for(int i = 1; i <= n; i++)
        q.push(i);
    while(!q.empty()){
        int u = q.front();
        q.pop();
        cnt[u]++;
        if(cnt[u] >= n){
            ans = false;
            break;
        }
        for(int e = head[u]; e; e = nxt[e]){
            if(dist[to[e]] > dist[u] + val[e]){
                dist[to[e]] = dist[u] + val[e];
                q.push(to[e]);
            }
        }
    }
    puts(ans ? "YES" : "NO");
    return 0;
}

G

#include <algorithm>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int INF = 0x3f3f3f3f;
const int N = 405;

int w[N][N];
int lx[N], ly[N];
int rmatch[N];
bool lvis[N], rvis[N];
int slack[N];

bool find(int i, int n) {
    lvis[i] = true;
    for (int j = 1; j <= n; j++)
        if (lx[i] + ly[j] == w[i][j] && !rvis[j]) {
            rvis[j] = true;
            if (!rmatch[j] || find(rmatch[j], n)) {
                rmatch[j] = i;
                return true;
            }
        } else {
            slack[j] = min(slack[j], lx[i] + ly[j] - w[i][j]);
        }
    return false;
}

void update(int n) {
    int dt = INF;
    for (int j = 1; j <= n; j++)
        if (!rvis[j]) dt = min(dt, slack[j]);
    for (int i = 1; i <= n; i++) {
        if (lvis[i]) lx[i] -= dt;
        if (rvis[i])
            ly[i] += dt;
        else
            slack[i] -= dt;
    }
}

int KM(int n) {
    for (int i = 1; i <= n; i++) {
        rmatch[i] = lx[i] = ly[i] = 0;
        for (int j = 1; j <= n; j++) {
            lx[i] = max(lx[i], w[i][j]);
        }
    }
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) {
            slack[j] = INF;
        }
        while (true) {
            for (int j = 1; j <= n; j++) {
                lvis[j] = rvis[j] = false;
            }
            if (find(i, n))
                break;
            else
                update(n);
        }
    }
    int res = 0;
    for (int i = 1; i <= n; i++) {
        res += lx[i] + ly[i];
    }
    return res;
}

struct node{
    long long c;
    int w;
    node(){}
    node(long long _c) : c(_c){}
    bool operator<(const node &b) const{
        return c < b.c;
    }
}nd[N];

long long a[N], b[N];

int main() {
    int n;
    scanf("%d", &n);
    for (int i = 1; i <= n; i++)
        scanf("%lld", &nd[i].c);
    for (int i = 1; i <= n; i++)
        scanf("%d", &nd[i].w);
    for (int i = 1; i <= n; i++)
        scanf("%lld", &a[i]);
    for (int i = 1; i <= n; i++)
        scanf("%lld", &b[i]);
    sort(nd + 1, nd + 1 + n);
    for (int i = 2; i <= n; i++)
        nd[i].w += nd[i - 1].w;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++)
            w[i][j] = (lower_bound(nd + 1, nd + 1 + n, node(a[i] + b[j])) - 1)->w;
    printf("%d", KM(n));
    return 0;
}

H

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <utility>
#include <vector>
using namespace std;
const int N = 1e6 + 1;
typedef pair<int, int> duo;

int t, n, m, u, v, cnt[N];
vector<int> g[N];

int fa[N], dfn[N], low[N], idx, stk[N], top;
int find(int x){
    return fa[x] == x ? x : fa[x] = find(fa[x]);
}
bool cut[N];
vector<int> dcc[N], belong[N];
int root, dcccnt;
void tarjan(int u){
    if(u == root && g[u].empty()){
        dcc[++dcccnt].push_back(1);
        return;
    }
    dfn[u] = low[u] = ++idx;
    stk[++top] = u;
    int cnt = 0;
    for(auto v : g[u]){
        if(!dfn[v]){
            tarjan(v);
            low[u] = min(low[u], low[v]);
            if(dfn[u] <= low[v]){
                cnt++;
                dcccnt++;
                if(u != root || cnt > 1)
                    cut[u] = true;
                int x;
                do{
                    x = stk[top--];
                    dcc[dcccnt].push_back(x);
                    belong[x].push_back(dcccnt);
                } while (x != v);
                dcc[dcccnt].push_back(u);
                belong[u].push_back(dcccnt);
            }
        }
        else low[u] = min(low[u], dfn[v]);
    }
}

int sz[N], szdcc[N];
bool candel[N], vis[N];
void dfs(int i, int from){
    vis[i] = true;
    sz[i] = 1;
    for(auto id : belong[i]) if(id != from){
        szdcc[id] = dcc[id].size() - 1;
        for(auto x : dcc[id]) if(cut[x] && x != i){
                dfs(x, id);
                szdcc[id] += sz[x] - 1;
        }
        if(szdcc[id] % 2 == 1)
            candel[i] = false;
        sz[i] += szdcc[id];
    }
    if((cnt[find(i)] - sz[i]) % 2 == 1)
        candel[i] = false;
}

duo vert[N];

int main(){
    // freopen("in.txt", "r", stdin);
    // freopen("std.txt", "w", stdout);
    scanf("%d", &t);
    while(t--){
        for(int i = 1; i <= dcccnt; i++)
            dcc[i].clear();
        dcccnt = 0;
        idx = 0;
        top = 0;
        long long ans = 0;
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= n; i++){
            vis[i] = false;
            g[i].clear();
            cut[i] = false;
            belong[i].clear();
            dfn[i] = low[i] = 0;
            scanf("%d", &vert[i].first);
            vert[i].second = i;
            ans += vert[i].first;
            fa[i] = i;
            cnt[i] = 1;
            candel[i] = true;
        }
        while(m--){
            scanf("%d%d", &u, &v);
            g[u].push_back(v);
            g[v].push_back(u);
            u = find(u), v = find(v);
            if(u != v){
                // printf("union %d %d\n", u, v);
                cnt[u] += cnt[v];
                fa[v] = u;
            }
        }
        for(int i = 1; i <= n; i++) if(!dfn[i]){
                root = i;
                tarjan(i);
        }
        for (int i = 1; i <= n; i++) if(cut[i] && !vis[i]){
                // printf("dfs %d\n", i);
                dfs(i, 0);
        }
        sort(vert + 1, vert + 1 + n);
        for (int i = 1; i <= n; i++)
            if(candel[vert[i].second]){
                int f = find(vert[i].second);
                // printf("f %d %d\n", vert[i].second, f);
                if(cnt[f] % 2 == 1){
                    ans -= vert[i].first * 2;
                    // printf("-= %d\n", vert[i].first);
                    cnt[f] = 0;
                }
            }
        // for (int i = 1; i <= dcccnt; i++){
            // printf("dcc %d: ", i);
            // for (auto x : dcc[i])
                // printf("%d ", x);
            // putchar('\n');
        // }
        // for (int i = 1; i <= n; i++)
            // printf("%d ", candel[i]);
        // putchar('\n');
        printf("%lld\n", ans);
    }
    return 0;
}

I

#include <cstdio>
#include <iostream>
using namespace std;
const int N = 1e6 + 1;

int n, m, u, v, x, y, head[N << 1], nxt[N << 1], to[N << 1], eid = 1;
void addedge(int u, int v){
    to[eid] = v;
    nxt[eid] = head[u];
    head[u] = eid++;
}

int dfn[N << 1], low[N << 1], idx, stk[N << 1], top;
bool ins[N << 1];
int scccnt, belong[N << 1];
void tarjan(int i){
    dfn[i] = low[i] = ++idx;
    stk[++top] = i;
    ins[i] = true;
    for(int e = head[i]; e; e = nxt[e]){
        if(!dfn[to[e]]){
            tarjan(to[e]);
            low[i] = min(low[i], low[to[e]]);
        }else if(ins[to[e]])
            low[i] = min(low[i], dfn[to[e]]);
    }
    if(low[i] == dfn[i]){
        scccnt++;
        while(stk[top] != i){
            belong[stk[top]] = scccnt;
            ins[stk[top]] = false;
            top--;
        }
        belong[i] = scccnt;
        ins[i] = false;
        top--;
    }
}

int main(){
    scanf("%d%d", &n, &m);
    while(m--){
        scanf("%d%d%d%d", &u, &x, &v, &y);
        addedge(u + n * x, v + n * !y);
        addedge(v + n * y, u + n * !x);
    }
    for(int i = 1; i <= 2 * n; i++)
        if(!dfn[i])
            tarjan(i);
    for(int i = 1; i <= n; i++)
        if(belong[i] == belong[i + n]){
            puts("NO");
            return 0;
        }
    puts("YES");
    // for(int i = 1; i <= n; i++)
        // printf("%d ", belong[i] < belong[i + n]);
    return 0;
}

J

#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
const int N = 1001, M = N * (N - 1);

int n, m, u, v, head[N], nxt[M], to[M], eid = 2, ans[4];
bool cutedge[M];
void addedge(int u, int v){
    to[eid] = v;
    nxt[eid] = head[u];
    head[u] = eid++;
}

int dfn[N], low[N], idx;

void bridge(int u, int pre){
    low[u] = dfn[u] = ++idx;
    for (int e = head[u]; e; e = nxt[e])
        if((e >> 1) != pre){
            int v = to[e];
            if(!dfn[v]){
                bridge(v, e >> 1);
                low[u] = min(low[u], low[v]);
                if(low[v] > dfn[u])
                    cutedge[e >> 1] = 1;
            }else
                low[u] = min(low[u], dfn[v]);
        }
}

bool cut[N];
int root, stk[N], top, dcccnt;
vector<int> dcc[N], belong[N];
void tarjan(int u, int pre){
    dfn[u] = low[u] = ++idx;
    stk[++top] = u;
    int cnt = 0;
    for (int e = head[u]; e; e = nxt[e]){
        int v = to[e];
        if(!dfn[v]){
            cnt++;
            tarjan(v, u);
            low[u] = min(low[u], low[v]);
            if(dfn[u] <= low[v]){
                dcccnt++;
                if(u != root || cnt > 1)
                    cut[u] = true;
                int x;
                do{
                    x = stk[top--];
                    dcc[dcccnt].push_back(x);
                    belong[x].push_back(dcccnt);
                } while (x != v);
                dcc[dcccnt].push_back(u);
                belong[u].push_back(dcccnt);
            }
        }
        else if(v != pre)
            low[u] = min(low[u], dfn[v]);
    }
}

int edgecnt[N];
bool cover[N];

int main(){
    scanf("%d%d", &n, &m);
    while(m--){
        scanf("%d%d", &u, &v);
        addedge(u, v);
        addedge(v, u);
    }
    idx = 0;
    memset(dfn, 0, sizeof(dfn));
    for (int i = 1; i <= n; i++)
        if(!dfn[i])
            bridge(i, 0);
    idx = 0;
    memset(dfn, 0, sizeof(dfn));
    for (root = 1; root <= n; root++)
        if(!dfn[root])
            tarjan(root, 0);
    for (int i = 1; i <= n; i++)
        ans[0] += cut[i];
    for (int i = 1; i < eid / 2; i++)
        ans[1] += cutedge[i];
    ans[2] = dcccnt;
    for (int u = 1; u <= n; u++){
        for (int e = head[u]; e; e = nxt[e]){
            int v = to[e];
            memset(cover, 0, sizeof(cover));
            for(int id : belong[u])
                cover[id] = true;
            for(int id : belong[v])
                if(cover[id]){
                    edgecnt[id]++;
                    break;
                }
        }
    }
    for (int i = 1; i <= dcccnt; i++)
        ans[3] = max(ans[3], edgecnt[i]);
    printf("%d %d %d %d", ans[0], ans[1], ans[2], ans[3] / 2);
    return 0;
}

K

#include <cstdio>
#include <vector>
using namespace std;
const int N = 5e5 + 1;

int n, q, u, v, head[N], nxt[N << 1], to[N << 1], eid = 1;
void addedge(int u, int v){
    to[eid] = v;
    nxt[eid] = head[u];
    head[u] = eid++;
}

struct node{
    int v, id;
    node(int _v, int _id) : v(_v), id(_id){}
};
int ans[N];
vector<node> qry[N];

int fa[N], dep[N];
int find(int x){
    return x == fa[x] ? x : fa[x] = find(fa[x]);
}
void dfs(int i, int from){
    for(auto nd : qry[i]){
        if(!ans[nd.id])
            ans[nd.id] = -1;
        else{
            int lca = find(nd.v);
            ans[nd.id] = dep[i] - dep[lca] + dep[nd.v] - dep[lca];
        }
    }
    for (int e = head[i]; e; e = nxt[e]) if(to[e] != from){
            dep[to[e]] = dep[i] + 1;
            dfs(to[e], i);
    }
    fa[i] = from;
}

int main(){
    scanf("%d%d", &n, &q);
    for (int i = 1; i < n; i++){
        scanf("%d%d", &u, &v);
        addedge(u, v);
        addedge(v, u);
    }
    for (int i = 1; i <= q; i++){
        scanf("%d%d", &u, &v);
        qry[u].push_back(node(v, i));
        qry[v].push_back(node(u, i));
    }
    for(int i = 1; i <= n; i++)
        fa[i] = i;
    dfs(1, 0);
    for(int i = 1; i <= q; i++)
        printf("%d\n", ans[i]);
    return 0;
}

L

#include <cstdio>
#include <vector>
using namespace std;
const int N = 101, M = 1001, W = 11, p = 10000;

int n, m, u, v, w;
struct edge{
    int u, v, w;
    edge(int _u, int _v, int _w) : u(_u), v(_v), w(_w){}
};
vector<edge> e[W], mst;

int fa[N], a[N][N], id[N], cnt;
int find(int x){
    return x == fa[x] ? x : fa[x] = find(fa[x]);
}

int det(int a[][N], int n, int p){
    int ans = 1, k;
    for (int i = 1; i <= n; i++){
        for(k = i; k <= n; k++)
            if(a[k][i])
                break;
        if(k > n)
            return 0;
        if(i != k){
            swap(a[i], a[k]);
            ans = -ans;
        }
        for (int j = i + 1; j <= n; j++){
            if(a[j][i] > a[i][i]){
                swap(a[j], a[i]);
                ans = -ans;
            }
            while(a[j][i]){
                int l = a[i][i] / a[j][i];
                for (int k = i; k <= n; k++)
                    a[i][k] = (a[i][k] + 1ll * (p - l) * a[j][k]) % p;
                swap(a[j], a[i]);
                ans = -ans;
            }
        }
        ans = 1ll * ans * a[i][i] % p;
    }
    return (ans + p) % p;
}

int main(){
    scanf("%d%d", &n, &m);
    while(m--){
        scanf("%d%d%d", &u, &v, &w);
        e[w].push_back(edge(u, v, w));
    }
    for (int i = 1; i <= n; i++)
        fa[i] = i;
    int sum = 0;
    for (int i = 1; i < W; i++){
        for(edge ed : e[i]){
            int u = find(ed.u);
            int v = find(ed.v);
            if(u != v){
                sum++;
                fa[v] = u;
                mst.push_back(ed);
            }
        }
    }
    if(sum != n - 1){
        putchar('0');
        return 0;
    }
    int ans = 1;
    for (int i = 1; i < W; i++){
        for (int j = 1; j <= n; j++)
            fa[j] = j;
        for (edge ed : mst)
            if(ed.w != i){
                int u = find(ed.u);
                int v = find(ed.v);
                if(u != v)
                    fa[v] = u;
            }
        cnt = 0;
        for (int j = 1; j <= n; j++)
            if(fa[j] == j)
                id[j] = ++cnt;
        if(cnt == 1)
            continue;
        for (int j = 1; j <= cnt; j++)
            for (int k = 1; k <= cnt; k++)
                a[j][k] = 0;
        for(edge ed : e[i]){
            int u = find(ed.u);
            int v = find(ed.v);
            if(u != v){
                u = id[u];
                v = id[v];
                a[u][v]--;
                a[v][u]--;
                a[u][u]++;
                a[v][v]++;
            }
        }
        for (int j = 1; j <= cnt; j++)
            for (int k = 1; k <= cnt; k++)
                a[j][k] = (a[j][k] % p + p) % p;
        ans = ans * det(a, cnt - 1, p) % p;
    }
    printf("%d", ans);
    return 0;
}

M

#include <cstdio>
#include <vector>
#include <queue>
#include <functional>
#include <cstring>
using namespace std;
const int N = 4e5 + 1;

template<class type>
struct leftist{
	struct node{
		type val = type();
		int ls = 0, rs = 0, d = 0;
		node(){}
		node(const type &_val) : val(_val){}
	};
	vector<node> data = vector<node>(1);
	int create(const type &val){
		data.push_back(node(val));
		return data.size() - 1;
	}
	int duplicate(node &nd){
		data.push_back(nd);
		return data.size() - 1;
	}
	int merge(int x, int y){
		if(!x || !y) return x | y;
		if(data[x].val > data[y].val) swap(x, y);
		x = duplicate(data[x]);
		int res = merge(data[x].rs, y);
		data[x].rs = res;
		if(data[data[x].ls].d < data[data[x].rs].d)
			swap(data[x].ls, data[x].rs);
		data[x].d = data[data[x].rs].d + 1;
		return x;
	}
};

struct edge{
	int u, v;
	long long w;
	edge(){}
	edge(int _u, int _v, long long _w) : u(_u), v(_v), w(_w){}
	bool operator>(const edge &b) const{
		return w > b.w;
	}
};

leftist<edge> heap;

int n, m, u, v, head[N], nxt[N], to[N], eid = 1;
long long k, w, val[N];
vector<edge> g[N];
void addedge(int u, int v, long long w){
	to[eid] = v;
	val[eid] = w;
	nxt[eid] = head[u];
	head[u] = eid++;
}

struct node{
	int id = 0;
	long long dist = 0;
	node(int _id, long long _dist) : id(_id), dist(_dist){}
	bool operator>(const node &b) const{
		return dist > b.dist;
	}
};
priority_queue<node, vector<node>, greater<node>> pq;
int fa[N], id[N];
long long dist[N];

void dfs(int u){
	bool del = false;
	for(edge e : g[u]){
		if(!del && e.v == fa[u] && dist[e.v] + e.w == dist[u]){
			del = true;
			continue;
		}
		e.w = dist[e.v] - dist[u] + e.w;
		if(!id[u]) id[u] = heap.create(e);
		else id[u] = heap.merge(id[u], heap.create(e));
	}
	if(id[fa[u]]) id[u] = id[u] ? heap.merge(id[fa[u]], id[u]) : id[fa[u]];
	for(int e = head[u]; e; e = nxt[e])
		if(!id[to[e]] && fa[to[e]] == u) dfs(to[e]);
}

priority_queue<edge, vector<edge>, greater<edge>> kth;

int main(){
	scanf("%d%d%lld", &n, &m, &k);
	for(int i = 1; i <= m; i++){
		scanf("%d%d%lld", &u, &v, &w);
//		if(u == n) continue;
		addedge(v, u, w);
		g[u].push_back(edge(u, v, w));
	}
	memset(dist + 1, 0x3f, sizeof(long long) * n);
	dist[n] = 0;
	pq.push(node(n, 0));
	while(!pq.empty()){
		node nd = pq.top();
		pq.pop();
		int u = nd.id;
		if(dist[u] < nd.dist) continue;
		for(int e = head[u]; e; e = nxt[e])
			if(dist[u] + val[e] < dist[to[e]]){
				dist[to[e]] = dist[u] + val[e];
				fa[to[e]] = u;
				pq.push(node(to[e], dist[to[e]]));
			}
	}
	dfs(n);
	kth.push(edge(0, 1, dist[1]));
	int cnt = 1;
	while(kth.size() && cnt < k){
		edge e = kth.top();
		kth.pop();
		cnt++;
		if(id[e.v]) kth.push(edge(id[e.v], heap.data[id[e.v]].val.v, e.w + heap.data[id[e.v]].val.w));
		if(heap.data[e.u].ls) kth.push(edge(heap.data[e.u].ls, heap.data[heap.data[e.u].ls].val.v, 
			e.w - heap.data[e.u].val.w + heap.data[heap.data[e.u].ls].val.w));
		if(heap.data[e.u].rs) kth.push(edge(heap.data[e.u].rs, heap.data[heap.data[e.u].rs].val.v, 
			e.w - heap.data[e.u].val.w + heap.data[heap.data[e.u].rs].val.w));
	}
	printf("%lld\n", kth.size() && kth.top().w != 0x3f3f3f3f3f3f3f3f ? kth.top().w : -1);
	return 0;
}

N

#include <cstdio>
#include <cstring>
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
const int N = 1001;
const long long INF = 0x3f3f3f3f3f3f3f3f;

int n, m, u, v, w, edge[N][N], order[N][N];
long long dist[N][N];

int main(){
    memset(edge, 0x3f, sizeof(edge));
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; i++)
        edge[i][i] = 0;
    while(m--){
        scanf("%d%d%d", &u, &v, &w);
        edge[u][v] = edge[v][u] = min(edge[u][v], w);
    }
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++)
            dist[i][j] = edge[i][j] == 0x3f3f3f3f ? INF : edge[i][j];
    for (int k = 1; k <= n; k++)
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= n; j++)
                dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]);
    for (int i = 1; i <= n; i++){
        for (int j = 1; j <= n; j++)
            order[i][j] = j;
        sort(order[i] + 1, order[i] + 1 + n, [&](int a, int b)
             { return dist[i][a] < dist[i][b]; });
    }
    long long ans = INF;
    for (int i = 1; i <= n; i++)
        ans = min(ans, dist[i][order[i][n]] * 2);
    for (int u = 1; u < n; u++)
        for (int v = u + 1; v <= n; v++)
            if(edge[u][v] != 0x3f3f3f3f)
                for (int p = n, j = n - 1; j >= 1; j--)
                    if (dist[v][order[u][j]] > dist[v][order[u][p]]){
                        ans = min(ans, dist[u][order[u][j]] + dist[v][order[u][p]] + edge[u][v]);
                        p = j;
                    }
    printf("%lld", ans);
    return 0;
}

O

#include <cstdio>
#include <queue>
#include <cstring>
using namespace std;
const int N = 1e5 + 1, M = 2e5 + 1;

int n, m, s, u, v, w, head[N], nxt[M], to[M], val[M], eid = 1;
void addedge(int u, int v, int w){
    to[eid] = v;
    val[eid] = w;
    nxt[eid] = head[u];
    head[u] = eid++;
}

long long dist[N];
struct node{
    long long dist;
    int i;
    node(long long _dist, int _i) : dist(_dist), i(_i){}
    bool operator<(const node &b) const{
        return dist > b.dist;
    }
};
priority_queue<node> q;

int main(){
    memset(dist, -1, sizeof(dist));
    scanf("%d%d%d", &n, &m, &s);
    while(m--){
        scanf("%d%d%d", &u, &v, &w);
        addedge(u, v, w);
    }
    dist[s] = 0;
    q.push(node(0, s));
    while(!q.empty()){
        if(q.top().dist > dist[q.top().i]){
            q.pop();
            continue;
        }
        int i = q.top().i;
        q.pop();
        for(int e = head[i]; e; e = nxt[e]){
            if(dist[to[e]] == -1 || dist[i] + val[e] < dist[to[e]]){
                dist[to[e]] = dist[i] + val[e];
                q.push(node(dist[to[e]], to[e]));
            }
        }
    }
    for (int i = 1; i <= n; i++)
        printf("%lld\n", dist[i]);
    return 0;
}

P

#include <cstdio>
#include <queue>
#include <cstring>
using namespace std;
const int N = 405, M = 2 * N * (N + 1), X[4] = {-1, 0, 1, 0}, Y[4] = {0, 1, 0, -1};

int n, m, unit, a[N][N], ver[N][N], hor[N][N];

long long dist[N][N];
int from[N][N];
struct node{
    long long dist;
    int x, y;
    node(long long _dist, int _x, int _y) : dist(_dist), x(_x), y(_y){}
    bool operator<(const node &b) const{
        return dist > b.dist;
    }
};
priority_queue<node> pq;
bool legal(int x, int y){
    return x >= 0 && y >= 0 && x <= n && y <= m;
}

bool del[N][N][4];

int head[4 * N * N], nxt[M * 4 + 8 * N * N], to[M * 4 + 8 * N * N], val[M * 4 + 8 * N * N], eid = 1;
void addedge(int u, int v, int w){
    to[eid] = v;
    val[eid] = w;
    nxt[eid] = head[u];
    head[u] = eid++;
}
void addundir(int u, int v, int w){
    addedge(u, v, w);
    addedge(v, u, w);
}

struct duo{
    long long d;
    int i;
    duo(long long _d, int _i) : d(_d), i(_i){}
    bool operator<(const duo &b) const{
        return d > b.d;
    }
};
priority_queue<duo> q;
long long d[4 * N * N];
long long dijkstra(int s, int t){
    memset(d, 0x3f, sizeof(d));
    d[s] = 0;
    q.push(duo(0, s));
    while(!q.empty()){
        int i = q.top().i;
        q.pop();
        for (int e = head[i]; e; e = nxt[e])
            if(d[to[e]] > d[i] + val[e]){
                d[to[e]] = d[i] + val[e];
                q.push(duo(d[to[e]], to[e]));
            }
    }
    return d[t];
}


int main(){
    scanf("%d%d", &n, &m);
    unit = (n + 1) * (m + 1);
    for (int i = 0; i < n; i++)
        for (int j = 0; j < m; j++){
            scanf("%d", &a[i][j]);
        	if(a[i][j]){
        		del[i][j][1] = true;
        		del[i][j][2] = true;
        		del[i + 1][j][0] = true;
        		del[i + 1][j][1] = true;
        		del[i][j + 1][2] = true;
        		del[i][j + 1][3] = true;
        		del[i + 1][j + 1][3] = true;
        		del[i + 1][j + 1][0] = true;
			}
		}
    for (int i = 0; i < n; i++)
        for (int j = 0; j <= m; j++){
            scanf("%d", &ver[i][j]);
            addundir(i * (m + 1) + j + 1 + 2 * unit, (i + 1) * (m + 1) + j + 1 + 1 * unit, ver[i][j]);
            addundir(i * (m + 1) + j + 1 + 3 * unit, (i + 1) * (m + 1) + j + 1 + 0 * unit, ver[i][j]);
        }
    for (int i = 0; i <= n; i++)
        for (int j = 0; j < m; j++){
            scanf("%d", &hor[i][j]);
            addundir(i * (m + 1) + j + 1 + 1 * unit, i * (m + 1) + j + 2 + 0 * unit, hor[i][j]);
            addundir(i * (m + 1) + j + 1 + 2 * unit, i * (m + 1) + j + 2 + 3 * unit, hor[i][j]);
        }
    memset(dist, 0x3f, sizeof(dist));
    dist[0][0] = 0;
    from[0][0] = -1;
    pq.push(node(0, 0, 0));
    while(!pq.empty()){
        int x = pq.top().x;
        int y = pq.top().y;
        pq.pop();
        if(x > 0 && dist[x - 1][y] > dist[x][y] + ver[x - 1][y]){
            dist[x - 1][y] = dist[x][y] + ver[x - 1][y];
            from[x - 1][y] = 0;
            pq.push(node(dist[x - 1][y], x - 1, y));
        }
        if(y < m && dist[x][y + 1] > dist[x][y] + hor[x][y]){
            dist[x][y + 1] = dist[x][y] + hor[x][y];
            from[x][y + 1] = 1;
            pq.push(node(dist[x][y + 1], x, y + 1));
        }
        if(x < n && dist[x + 1][y] > dist[x][y] + ver[x][y]){
            dist[x + 1][y] = dist[x][y] + ver[x][y];
            from[x + 1][y] = 2;
            pq.push(node(dist[x + 1][y], x + 1, y));
        }
        if(y > 0 && dist[x][y - 1] > dist[x][y] + hor[x][y - 1]){
            dist[x][y - 1] = dist[x][y] + hor[x][y - 1];
            from[x][y - 1] = 3;
            pq.push(node(dist[x][y - 1], x, y - 1));
        }
    }
    for (int i = 0; i < n; i++)
        for (int j = 0; j < m; j++)
            if(a[i][j]){
                int x = i, y = j;
                while(from[x][y] != -1){
                    int t = from[x][y];
                    from[x][y] = -1;
                    del[x][y][(t + 2) % 4] = 1;
                    x -= X[t], y -= Y[t];
                    del[x][y][t] = 1;
                }
            }
    del[0][0][0] = 1;
    del[0][0][3] = 1;
    for (int i = 0; i <= n; i++)
        for (int j = 0; j <= m; j++)
            for (int t = 0; t < 4; t++)
                if(!del[i][j][t])
                    addundir(i * (m + 1) + j + 1 + t * unit, i * (m + 1) + j + 1 + (t + 1) % 4 * unit, 0);
    printf("%lld", dijkstra(1 + unit, 1 + 3 * unit));
    return 0;
}

Q

#include <cstdio>
#include <iostream>
#define le (i << 1)
#define ri (i << 1 | 1)
using namespace std;
const int N = 1e5 + 1;
const long long INF = 0x3f3f3f3f3f3f3f3f;

int n, d, a[N], pos[2][N << 2];
bool same[2][N << 2];
long long ans[2][N << 2], num[2][N << 2], val[2][N << 2];

void pushup(int id, int i){
    num[id][i] = max(num[id][le], num[id][ri]);
    if(same[id][le] && same[id][ri] && num[id][le] == num[id][ri])
        same[id][i] = true;
    val[id][i] = min(val[id][le], val[id][ri]);
    if(ans[id][le] < ans[id][ri]){
        ans[id][i] = ans[id][le];
        pos[id][i] = pos[id][le];
    }else{
        ans[id][i] = ans[id][ri];
        pos[id][i] = pos[id][ri];
    }
}

void pushdown(int id, int i){
    if(same[id][i]){
        same[id][le] = same[id][ri] = true;
        num[id][le] = num[id][ri] = num[id][i];
        ans[id][le] = val[id][le] + num[id][le];
        ans[id][ri] = val[id][ri] + num[id][ri];
        same[id][i] = false;
    }
}

void build(int i, int l, int r){
    num[0][i] = INF;
    num[1][i] = INF;
    same[0][i] = true;
    same[1][i] = true;
    if(l == r){
        val[0][i] = a[l] + 1ll * l * d;
        val[1][i] = a[l] - 1ll * l * d;
        ans[0][i] = val[0][i] + num[0][i];
        ans[1][i] = val[1][i] + num[1][i];
        pos[0][i] = l;
        pos[1][i] = l;
        return;
    }
    int mid = (l + r) >> 1;
    build(le, l, mid);
    build(ri, mid + 1, r);
    pushup(0, i);
    pushup(1, i);
}

int L, R;
long long K;
void tomin(int id, int i, int l, int r){
    if(num[id][i] <= K)
        return;
    if(l >= L && r <= R && same[id][i] && num[id][i] > K){
        same[id][i] = true;
        num[id][i] = K;
        ans[id][i] = val[id][i] + num[id][i];
        return;
    }
    pushdown(id, i);
    int mid = (l + r) >> 1;
    if(mid >= L)
        tomin(id, le, l, mid);
    if(mid < R)
        tomin(id, ri, mid + 1, r);
    pushup(id, i);
}
int P;
void del(int id, int i, int l, int r){
    if(l == r){
        val[id][i] = INF;
        ans[id][i] = val[id][i] + num[id][i];
        return;
    }
    pushdown(id, i);
    int mid = (l + r) >> 1;
    if(mid >= P)
        del(id, le, l, mid);
    else
        del(id, ri, mid + 1, r);
    pushup(id, i);
}

int main(){
    scanf("%d%d", &n, &d);
    for (int i = 1; i <= n; i++)
        scanf("%d", &a[i]);
    build(1, 1, n);
    same[0][1] = same[1][1] = true;
    ans[0][1] = ans[1][1] = INF;
    int p = 1;
    long long sum = 0;
    for (int i = 1; i < n; i++){
        P = p;
        del(0, 1, 1, n);
        del(1, 1, 1, n);
        L = p + 1, R = n, K = -1ll * p * d + a[p];
        if(L <= R)
            tomin(0, 1, 1, n);
        L = 1, R = p - 1, K = 1ll * p * d + a[p];
        if(L <= R)
            tomin(1, 1, 1, n);
        if(ans[0][1] < ans[1][1]){
            p = pos[0][1];
            sum += ans[0][1];
        }else{
            p = pos[1][1];
            sum += ans[1][1];
        }
    }
    printf("%lld", sum);
    return 0;
}

R

#include <cstdio>
#include <cstring>
using namespace std;
const int N = 101, M = 10001, INF = 0x7fffffff;

int n, m, s, u[M], v[M], w[M], id[N], pre[N], minw[N], src, idx;
int vis[N];

int zhuliu(){
    w[0] = INF;
    int ret = 0;
    while(true){
        memset(pre, 0, sizeof(pre));
        for (int i = 1; i <= m; i++)
            if(u[i] != v[i] && (!pre[v[i]] || minw[v[i]] > w[i])){
                pre[v[i]] = u[i];
                minw[v[i]] = w[i];
            }
        for (int i = 1; i <= n; i++)
            if(i != s && !pre[i])
                return -1;
        idx = 0;
        memset(id, 0, sizeof(id));
        memset(vis, 0, sizeof(vis));
        vis[s] = -1;
        for (int i = 1; i <= n; i++)
            if(i != s){
                ret += minw[i];
                int j = i;
                while(!vis[j]){
                    vis[j] = i;
                    j = pre[j];
                }
                if(j != s && vis[j] == i){
                    id[j] = ++idx;
                    for (int k = pre[j]; k != j; k = pre[k])
                        id[k] = idx;
                }
            }
        if(idx == 0)
            break;
        for (int i = 1; i <= n; i++)
            if(!id[i])
                id[i] = ++idx;
        for (int i = 1; i <= m; i++){
            if (id[u[i]] != id[v[i]])
                w[i] -= minw[v[i]];
            u[i] = id[u[i]], v[i] = id[v[i]];
        }
        s = id[s];
        n = idx;
    }
    return ret;
}

int main(){
    scanf("%d%d%d", &n, &m, &s);
    for (int i = 1; i <= m; i++)
        scanf("%d%d%d", &u[i], &v[i], &w[i]);
    printf("%d", zhuliu());
    return 0;
}

S

#include <cstdio>
#include <cstring>
#include <queue>
#include <iostream>
using namespace std;
const int N = 1001, M = 2e5 + 1;

int n, m, u, v, match[N], col[N], pre[N], raw[N], fa[N], head[N], nxt[M << 1], to[M << 1], eid = 1;
void addedge(int u, int v){
	to[eid] = v;
	nxt[eid] = head[u];
	head[u] = eid++;
}
int find(int x){
	return x == fa[x] ? x : fa[x] = find(fa[x]);
}

int tag[N], idx;
int lca(int u, int v){
	u = find(u);
	v = find(v);
	idx++;
	do{
		tag[u] = idx;
		u = find(pre[match[u]]);
		if(v) swap(u, v);
	}while(tag[u] != idx);
	return u;
}

queue<int> q;

void blossom(int u, int v, int m){
	while(find(u) != m){
		pre[u] = v;
		v = match[u];
		if(col[v] == 0){
			col[v] = 1;
			q.push(v);
		}
		fa[u] = m;
		fa[v] = m;
		u = pre[v];
	}
}

int solve(int u){
	q = queue<int>();
	memcpy(fa + 1, raw + 1, sizeof(int) * n);
	memset(col + 1, -1, sizeof(int) * n);
	pre[u] = 0;
	col[u] = 1;
	q.push(u);
	while(!q.empty()){
		int u = q.front();
		q.pop();
		for(int e = head[u]; e; e = nxt[e]){
			int v = to[e];
			if(find(u) == find(v) || col[v] == 0) continue;
			if(col[v] == -1){
				pre[v] = u;
				col[v] = 0;
				if(!match[v]){
					for(int _v = match[pre[v]]; v; v = _v, _v = match[pre[v]]){
						match[v] = pre[v];
						match[pre[v]] = v;
					}
					return 1;
				}
				col[match[v]] = 1;
				q.push(match[v]);
			}else{
				int m = lca(u, v);
				blossom(u, v, m);
				blossom(v, u, m);
			}
		}
	}
	return 0;
}

int main(){
	scanf("%d%d", &n, &m);
	for(int i = 1; i <= n; i++)
		raw[i] = i;
	while(m--){
		scanf("%d%d", &u, &v);
		addedge(u, v);
		addedge(v, u);
	}
	int ans = 0;
	for(int i = 1; i <= n; i++)
		if(!match[i]) ans += solve(i);
	printf("%d\n", ans);
	return 0;
}

T

#include <cstring>
#include <iostream>
using namespace std;
const int MAX_N = 1005;
const int MAX_M = 1000005;
struct Edge {
    int v, next;
} e[MAX_M];
int p[MAX_N], eid;
void init() {
    memset(p, -1, sizeof(p));
    eid = 0;
}
void insert(int u, int v) {
    e[eid].v = v;
    e[eid].next = p[u];
    p[u] = eid++;
}

bool vis[MAX_N];
int rmatch[MAX_N];
bool dfs(int u) {
    for (int i = p[u]; i != -1; i = e[i].next) {
        int v = e[i].v;
        if (!vis[v]) {
            vis[v] = true;
            if (rmatch[v] == -1 || dfs(rmatch[v])) {
                rmatch[v] = u;
                return true;
            }
        }
    }
    return false;
}

int hungary(int n) {
    int res = 0;
    memset(rmatch, -1, sizeof(rmatch));
    for (int i = 1; i <= n; ++i) {
        memset(vis, 0, sizeof(vis));
        res += dfs(i);
    }
    return res;
}

int path[MAX_N];
int main() {
	int n, m;
    scanf("%d%d", &n, &m);
    init();
    for (int i = 0; i < m; i++) {
        int u, v;
        scanf("%d%d", &u, &v);
        insert(u, v);
    }
    printf("%d", n - hungary(n));
    return 0;
}
posted @ 2022-04-23 14:27  SpaceJellyfish  阅读(112)  评论(0)    收藏  举报