2017-10-16校内训练题题解

贰零壹柒年拾月拾陆日,傻逼题战役。
aziint:颅骨以下被击穿,脑子正迅速进水!

T1

先缩点。第一问求入度为零的点的个数,第二问 max(,) 。注意特判只有一个scc的情况。
然而我在第一问时还写了个染色,结果速度如龟。

#include<bits/stdc++.h>
using namespace std;

inline int read() {
    int x = 0, flag = 1; char ch = getchar();
    while (ch > '9' || ch < '0') { if (ch == '-') flag = -1; ch = getchar(); }
    while (ch <= '9' && ch >= '0') { x = x * 10 + ch - '0'; ch = getchar(); }
    return x * flag;
}

#define N 101
#define rep(ii, aa, bb) for (int ii = aa; ii <= bb; ii++)
#define fech(i, x) for (int i = 0; i < x.size(); i++)

int n;
bool g[N][N];
struct edge { int u, v; }e[N * N];
int tot;

int ind, scc;
int belong[N];
int dfn[N], low[N];
stack<int> stk;
bool inStk[N];

int inE[N], otE[N];

int ans1;

void tarjan(int u) {
    dfn[u] = low[u] = ++ind;
    stk.push(u); inStk[u] = 1;
    rep(i, 1, n) if(g[u][i])
        if(!dfn[i]) tarjan(i), low[u] = min(low[u], low[i]);
        else if(inStk[i]) low[u] = min(low[u], dfn[i]);
    int v = -1;
    if(dfn[u] == low[u]) {
        scc++;
        while(u != v) {
            v = stk.top(); stk.pop(); inStk[v] = 0;
            belong[v] = scc;
        }
    }
}

int main() {
    cin >> n;
    rep(i, 1, n)
        while(1) {
            int v = read();
            if(!v) break;
            g[i][v] = 1;
            e[++tot].u = i, e[tot].v = v;
        }
    rep(i, 1, n) if(!dfn[i]) tarjan(i);
    ans1 = 0;
    memset(g, 0, sizeof g);
    rep(i, 1, tot) if(belong[e[i].u] != belong[e[i].v]) {
        int u = belong[e[i].u], v = belong[e[i].v];
        g[u][v] = 1, otE[u]=1, inE[v]= 1;
    }
    rep(i, 1, scc) if(!inE[i]) ans1++;
    if(scc == 1) {printf("1\n0"); return 0;}
    int t1 = 0, t2 = 0;
    rep(i, 1, scc) {
        if(!inE[i]) t1++;
        if(!otE[i]) t2++;
    }
    printf("%d\n%d", ans1, max(t1, t2));
    return 0;
}

T2

两遍spfa,一遍正一遍反,查询 O(1)
开考最先写的就是这道题。得益于我 450+ 每分钟的打字速度,以及超强的背板能力, 20min就打完了这道题,但是我开了个vector < int > g[3][N],顶到上界的下面一点,本地AC提交全RE。
辣鸡floj毁我人生。

#include<bits/stdc++.h>
using namespace std;

inline int read() {
    int x = 0, flag = 1; char ch = getchar();
    while (ch > '9' || ch < '0') { if (ch == '-') flag = -1; ch = getchar(); }
    while (ch <= '9' && ch >= '0') { x = x * 10 + ch - '0'; ch = getchar(); }
    return x * flag;
}
inline void write(int x) { if (x >= 10) write(x / 10); putchar(x % 10 + '0'); }

#define N 100001
#define rep(ii, aa, bb) for (int ii = aa; ii <= bb; ii++)
#define fech(i, x) for (int i = 0; i < x.size(); i++)
#define pii pair<int, int>
#define mp make_pair
#define to first
#define wt second
#define INF 0x7fffffff

int n;
vector<pii> g[5][N];

deque<int> q;
int dis[5][N];
bool vis[N];
void spfa(int x) {
    rep(i, 1, n) dis[x][i] = INF;
    dis[x][1] = 0;
    q.push_back(1); vis[1] = 1;
    while(q.size()) {
        int u = q.front(); q.pop_front(); vis[u] = 0;
        fech(i, g[x][u]) {
            int v = g[x][u][i].to, w = g[x][u][i].wt;
            if(dis[x][v] > dis[x][u] + w) {
                dis[x][v] = dis[x][u] + w;
                if(!vis[v])
                    if(rand() & 1) q.push_back(v), vis[v] = 1;
                    else q.push_front(v), vis[v] = 1;
            }
        }
    }
}

int main() {
    srand(19270723 + 19491001);
    cin >> n; int m = read();
    while(m--) {
        int u = read(), v = read(), w = read();
        g[1][u].push_back(mp(v, w));
        g[2][v].push_back(mp(u, w));
    }
    spfa(1), spfa(2);
    int q = read();
    while(q --) {
        int u = read(), v = read();
        if(dis[2][u] < INF && dis[1][v] < INF) write(dis[2][u] + dis[1][v]), puts("");
        else puts("-1");
    }
    return 0;
}

T3

kruskal,然后用倍增求出两点到他们最近公共祖先的路径长度。复杂度 O(mlog2m+(n+q)log2n)
听说@yy这道题写了树剖,%%%orz。

#include<map>
#include<cstdio>
#include<vector>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

inline int read() {
    int x = 0, flag = 1; char ch = getchar();
    while (ch > '9' || ch < '0') { if (ch == '-') flag = -1; ch = getchar(); }
    while (ch <= '9' && ch >= '0') { x = x * 10 + ch - '0'; ch = getchar(); }
    return x * flag;
}
inline void write(int x) { if (x >= 10) write(x / 10); putchar(x % 10 + '0'); }

#define N 100050
#define rep(i, a, b) for (int i = a; i <= b; i++)
#define drp(i, a, b) for (int i = a; i >= b; i--)
#define fech(i, x) for (int i = 0; i < x.size(); i++)
#define pii pair<int, int>
#define mp make_pair
#define to first
#define wt second

int n;
map<string, int> name;
vector<pii > tr[N];
struct node { int u, v, w; }e[N];
bool cmp(const node a, const node b) { return a.w < b.w; }

int pre[N];
int find(int x) { return x == pre[x] ? x : pre[x] = find(pre[x]); }

int fa[N][20], anc[N][20], dep[N];
void dfs(int u, int f) {
    fech(i, tr[u]) if (tr[u][i].to ^ f) {
        int v = tr[u][i].to;
        dep[v] = dep[u] + 1;
        fa[v][0] = u;
        anc[v][0] = tr[u][i].wt;
        dfs(v, u);
    }
}

int query(int x, int y) {
    int ans = 0;
    if (dep[x] < dep[y]) swap(x, y);
    int d = dep[x] - dep[y];
    rep(i, 0, 17) if (d & 1 << i) ans = max(ans, anc[x][i]), x = fa[x][i];
    drp(i, 17, 0) if (anc[x][i] ^ anc[y][i])
        ans = max(ans, anc[x][i]), ans = max(ans, anc[y][i]),
        x = fa[x][i], y = fa[y][i];
    if (x ^ y) ans = max(ans, anc[x][0]), ans = max(ans, anc[y][0]);
    return ans;
}

int main() {
    cin >> n; int m = read();
    rep(i, 1, n) {
        string s; cin >> s;
        name[s] = i; pre[i] = i;
    }
    rep(i, 1, m) {
        string s1, s2; cin >> s1 >> s2;
        int u = name[s1], v = name[s2];
        e[i].u = u, e[i].v = v, e[i].w = read();
    }
    sort(e + 1, e + 1 + m, cmp);
    int cnt = 0;
    rep(i, 1, m) {
        int u = e[i].u, v = e[i].v, w = e[i].w;
        int uu = find(u), vv = find(v);
        if (uu != vv) {
            pre[uu] = vv;
            tr[u].push_back(mp(v, w)), tr[v].push_back(mp(u, w));
            if (++cnt == n - 1) break;
        }
    }
    dfs(1, 0);

    rep(i, 1, 17) rep(j, 2, n)
        fa[j][i] = fa[fa[j][i - 1]][i - 1],
        anc[j][i] = max(anc[j][i - 1], anc[fa[j][i - 1]][i - 1]);

    int q = read();
    while (q--) {
        string s1, s2; cin >> s1 >> s2;
        write(query(name[s1], name[s2])), puts("");
    }
    return 0;
}

后续

考完一群人*floj的榜,于是我因为滥用熟练使用stl跑的比谁都慢。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值