日常

码风又变了。

BZOJ1093:

码了好久,正解挺套路的。tarjan缩点+拓扑序DP。
DP求缩完点后DAG上的最长链和最长链条数。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <stack>
#include <vector>
#include <queue>
const int MAXN = 100000;
using namespace std;

inline int read() {
    int x = 0, w = 1; 
    char c = ' ';

    while (c < '0' || c > '9') {
        c = getchar();
        if (c == '-') w = -1;
    }
    while (c >= '0' && c <= '9') {
        x = (x << 1) + (x << 3) + (c ^ 48);
        c = getchar();
    }

    return x * w;
}

struct Edge {
    int to, nxt;
}edge[1000000 + 5];

int n, m, x, head[MAXN + 5], tot;
int ind, dfn[MAXN + 5], low[MAXN + 5], cnt, belong[MAXN + 5], num[MAXN + 5];
bool inSta[MAXN + 5];
stack < int > S;

vector < int > newEdge[MAXN + 5];
queue < int > Q;
int inDegree[MAXN + 5], f[MAXN + 5], maxv[MAXN + 5], pre[MAXN + 5];

inline void add(int u, int v) {
    edge[tot] = (Edge) {v, head[u]};
    head[u] = tot++;
}

inline void newAdd(int u, int v) {
    newEdge[u].push_back(v);
    ++inDegree[v];
}

int tarjan(int u) {
    dfn[u] = low[u] = ++ind;
    S.push(u);
    inSta[u] = true;
        
    for (int i = head[u]; ~i; i = edge[i].nxt) {
        int v = edge[i].to;

        if (!dfn[v]) {
           tarjan(v);
           low[u] = min(low[u], low[v]);
        }
        else if (inSta[v])
            low[u] = min(low[u], dfn[v]);
    }

    if (dfn[u] == low[u]) {
        int k; 
        ++cnt;

        do {
            k = S.top();
            belong[k] = cnt; 
            ++num[cnt];
            inSta[k] = false;
            S.pop();
        }while (k != u);
    }
}

void topSort() {
    for (int i = 1; i <= cnt; ++i)
        if (!inDegree[i]) {
            Q.push(i);
            maxv[i] = num[i];
            f[i] = 1;
        }

    while (!Q.empty()) {
        int u = Q.front(); 
        Q.pop();

        for (int i = 0; i < newEdge[u].size(); ++i) {
            int v = newEdge[u][i]; 
            
            --inDegree[v];
            if (!inDegree[v]) Q.push(v);

            if (pre[v] == u) continue;

            if (maxv[u] + num[v] > maxv[v]) {
                maxv[v] = maxv[u] + num[v];
                f[v] = f[u];
            }
            else if (maxv[u] + num[v] == maxv[v]) 
                f[v] = (f[v] + f[u]) % x;
            
            pre[v] = u;
        }

    }
}

void init() {
    memset(head, -1, sizeof(head));
    tot = 0;
    cnt = 0;
    ind = 0;

    n = read();
    m = read();
    x = read();

    for (int i = 1; i <= m; ++i) {
        int u = read(), v = read();
        
        add(u, v);
    }
}

int main() {
    init();

    for (int i = 1; i <= n; ++i) 
        if (!dfn[i]) tarjan(i);
    
    for (int u = 1; u <= n; ++u) {
        for (int i = head[u]; ~i; i = edge[i].nxt) {
            int v = edge[i].to;

            if (belong[u] ^ belong[v]) newAdd(belong[u], belong[v]);
        }
    }

    topSort();

    int sum = 0, ans = 0;

    for (int i = 1; i <= cnt; ++i)
        if (ans < maxv[i]) {
            ans = maxv[i];
            sum = f[i];
        } 
        else if (ans == maxv[i])
            sum = (sum + f[i]) % x;

    printf("%d\n%d", ans, sum);

    return 0;
}

UOJ #3

\(LCT\)动态维护最小生成树。
把边权看成点权。
怕被卡常数,所以用并查集维护连通性。

代码写起来挺无脑的。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define ls ch[0]
#define rs ch[1]
#define lson s[x].ls
#define rson s[x].rs
#define father s[x].fa
const int MAXN = 200000;
const int INF = 0x3f3f3f3f;
using namespace std;

inline int min(int a, int b) {
    return a < b ? a : b;
}

inline int read() {
    int x = 0, w = 1; 
    char c = ' ';

    while (c < '0' || c > '9') {
        c = getchar();
        if (c == '-') w = -1;
    }
    while (c >= '0' && c <= '9') {
        x = (x << 1) + (x << 3) + (c ^ 48);
        c = getchar();
    }

    return x * w;
}

struct Ufs {
    int fa[MAXN + 5], rk[MAXN + 5];

    Ufs() {
        for (int i = 1; i <= MAXN; ++i) {
            fa[i] = i;
            rk[i] = 1;
        }
    }

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

    void unionSet(int x, int y) {
        int p = find(x), q = find(y);

        if (p != q) {
            if (rk[p] < rk[q]) 
                fa[p] = q;
            else {
                if (rk[p] == rk[q]) ++rk[q];
                fa[q] = p;
            }
        }
    }
}S;

struct LinkCutTree {

    struct Node {
        int ch[2], fa, data, mx; 
        bool rev;
    }s[MAXN + 5];

    int st[MAXN + 5], top;

    void pushUp(int x) {
        int &mx = s[x].mx = x; 

        if (lson && s[s[lson].mx].data > s[mx].data) mx = s[lson].mx;
        if (rson && s[s[rson].mx].data > s[mx].data) mx = s[rson].mx;
    }

    void pushDown(int x) {
        if (s[x].rev) {
            s[x].rev ^= 1;
            s[lson].rev ^= 1;
            s[rson].rev ^= 1;
            swap(lson, rson);
        }
    }

    bool isRoot(int x) {
        return s[father].ls != x && s[father].rs != x;
    }

    void rotate(int x) {
        int y = father, z = s[y].fa, l, r;

        if (s[y].ls == x) l = 0; else l = 1; 
        r = l ^ 1;

        if (!isRoot(y)) 
            if (s[z].ls == y) s[z].ls = x; else s[z].rs = x;
        father = z;
        s[y].fa = x;
        s[ s[x].ch[r] ].fa = y;
        s[y].ch[l] = s[x].ch[r];
        s[x].ch[r] = y;

        pushUp(y);
        pushUp(x);
    }

    void splay(int x) {
        top = 0;
        st[++top] = x;
        for (int i = x; !isRoot(i); i = s[i].fa)
            st[++top] = s[i].fa;
        for (int i = top; i; --i)
            pushDown(st[i]);

        while (!isRoot(x)) {
            int y = father, z = s[y].fa;

            if (!isRoot(y))
                if (s[y].ls == x ^ s[z].ls == y) rotate(x); else rotate(y);
            rotate(x);
        }
    }

    void access(int x) {
        for (int last = 0; x; last = x, x = father) {
            splay(x);
            rson = last;
            pushUp(x);
        }
    }

    void makeRoot(int x) {
        access(x);
        splay(x);
        s[x].rev ^= 1;
    }
     
    void link(int x, int y) {
        makeRoot(x);
        father = y;
    }

    void cut(int x, int y) {
        makeRoot(x);
        access(y);
        splay(y);

        if (s[y].ls == x) s[y].ls = father = 0;
    }

    int query(int x, int y) {
        makeRoot(x);
        access(y);
        splay(y);

        return s[y].mx;
    }
}Lct;

struct Edge {
    int u, v, a, b;

    bool operator < (const Edge &n) const {
        if (b == n.b) return a < n.a; else return b < n.b;
    }
}edge[MAXN + 5];

int n, m, ans;

void init() {
    n = read();
    m = read();
    
    for (int i = 1; i <= m; ++i) {
        edge[i].u = read();
        edge[i].v = read();
        edge[i].a = read();
        edge[i].b = read();
    }

    ans = INF;
}

int main() {
    init();

    sort(edge + 1, edge + 1 + m);

    for (int i = 1; i <= m; ++i)
        Lct.s[i + n].data = edge[i].a;

    for (int i = 1; i <= m; ++i) {
        int u = edge[i].u, v = edge[i].v;
        bool f = true;

        if (S.find(u) == S.find(v)) {
            int mx = Lct.query(u, v);

            if (Lct.s[mx].data > edge[i].a) {
                Lct.cut(edge[mx - n].u, mx);
                Lct.cut(mx, edge[mx - n].v);
            }
            else
                f = false;
        }
        else 
            S.unionSet(u, v);

        if (f) {
            Lct.link(u, i + n);
            Lct.link(i + n, v);
        }

        if (S.find(1) == S.find(n)) {
            int mx = Lct.query(1, n);
            ans = min(ans, Lct.s[mx].data + edge[i].b);
        }
    }
    
    printf("%d\n", ans == INF ? -1 : ans);

    return 0;
}

BZOJ2152

点分治模板题,没什么难度。

#include <iostream>
#include <cstdio>
#include <cstring>
#define max(a, b) (a < b ? b : a)
const int MAXN = 40000; 
using namespace std;

inline int read() {
    int x = 0, w = 1;
    char c = ' ';

    while (c < '0' || c > '9') {
        c = getchar();
        if (c == '-') w = -1;
    } 
    while (c >= '0' && c <= '9') {
        x = (x << 1) + (x << 3) + (c ^ 48);
        c = getchar();
    }

    return x * w;
}

struct Edge {
    int to, w, nxt;
}edge[MAXN + 5];

int head[MAXN + 5], tot;

bool vis[MAXN + 5];
int size[MAXN + 5], depth[MAXN + 5], maxSon[MAXN + 5], sz[MAXN + 5], num[MAXN + 5], total, rt;
int ans;

void add(int u, int v, int w) {
    edge[tot] = (Edge) {v, w, head[u]};
    head[u] = tot++;

    edge[tot] = (Edge) {u, w, head[v]};
    head[v] = tot++;
}

void getCentre(int u, int fa) {
    sz[u] = 1; 
    maxSon[u] = 0;

    for (int i = head[u]; ~i; i = edge[i].nxt) {
        int v = edge[i].to, w = edge[i].w;
    
        if (v != fa && !vis[v]) {
            getCentre(v, u);
            sz[u] += sz[v];
            maxSon[u] = max(maxSon[u], sz[v]);
        }
    }

    maxSon[u] = max(maxSon[u], total - sz[u]);

    if (maxSon[u] < maxSon[rt]) rt = u;
}

void getDepths(int u, int fa) {
    ++num[depth[u]];

    for (int i = head[u]; ~i; i = edge[i].nxt) {
        int v = edge[i].to, w = edge[i].w;

        if (v != fa && !vis[v]) {
            depth[v] = (depth[u] + w) % 3;
            getDepths(v, u);
        }
    }
}

int calc(int u, int w) {
    num[0] = num[1] = num[2] = 0;
    depth[u] = w;

    getDepths(u, -1);

    return num[1] * num[2] * 2 + num[0] * num[0];
}

void divideAndConquer(int u) {
    ans += calc(u, 0);
    vis[u] = true;

    for (int i = head[u]; ~i; i = edge[i].nxt) {
        int v = edge[i].to, w = edge[i].w;

        if (!vis[v]) {
            ans -= calc(v, w);
            rt = 0;
            total = sz[v];

            getCentre(v, -1);

            divideAndConquer(rt);
        }
    }
}

int n;

void init() {
    memset(head, -1, sizeof(head));

    n = read();

    for (int i = 1; i < n; ++i) {
        int u = read(), v = read(), w = read();

        add(u, v, w % 3);
    }

    total = n; 
    rt = ans = 0;
    maxSon[rt] = n;
    getCentre(1, -1);
}

inline int gcd(int a, int b) {
    return b ? gcd(b, a % b) : a;
}

int main() {
    init();

    divideAndConquer(rt);

    int tmp = gcd(ans, n * n);

    printf("%d/%d\n", ans / tmp, n * n / tmp);

    return 0;
}

洛谷P2365

可以单调队列优化,懒得写了。

#include <iostream>
#include <cstdio>
#include <cstring>
#define min(a, b) (a < b ? a : b)
const int MAXN = 5000;
using namespace std;

inline int read() {
    int x = 0, w = 1;
    char c = ' ';

    while (c < '0' || c > '9') {
         c = getchar();
         if (c == '-') w = -1;
    }
    while (c >= '0' && c <= '9') {
        x = (x << 1) + (x << 3) + (c ^ 48); 
        c = getchar();
    }

    return x * w;
}

int f[MAXN + 5], t[MAXN + 5], dp[MAXN + 5];
int n, s;

void init() {
    memset(dp, 0x3f, sizeof(dp));

    n = read();
    s = read();

    for (int i = 1; i <= n; ++i) {
        t[i] = read() + t[i - 1];
        f[i] = read() + f[i - 1];
    }
}

int main() {
    init();
    
    dp[0] = 0;
    for (int i = 1; i <= n; ++i) 
        for (int j = 1; j <= i; ++j)
            dp[i] = min(dp[i], dp[j - 1] + t[i] * (f[i] - f[j - 1]) + s * (f[n] - f[j - 1]));

    printf("%d\n", dp[n]);

    return 0;
}

POJ1180:

上一题的单调队列优化版。

AC代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#define min(a, b) (a < b ? a : b)
const int MAXN = 10000;
using namespace std;

inline int read() {
    int x = 0, w = 1;
    char c = ' ';

    while (c < '0' || c > '9') {
         c = getchar();
         if (c == '-') w = -1;
    }
    while (c >= '0' && c <= '9') {
        x = (x << 1) + (x << 3) + (c ^ 48); 
        c = getchar();
    }

    return x * w;
}

int c[MAXN + 5], t[MAXN + 5], dp[MAXN + 5];
int n, s;
int f, r, que[MAXN + 5];

void init() {
    memset(dp, 0x3f, sizeof(dp));

    n = read();
    s = read();

    for (int i = 1; i <= n; ++i) {
        t[i] = read() + t[i - 1];
        c[i] = read() + c[i - 1];
    }
    
    f = 0;
    r = 0;
    que[f] = 0;
}

int main() {
    init();
    
    dp[0] = 0;
    for (int i = 1; i <= n; ++i) {
        while (f < r && dp[que[f + 1]] - dp[que[f]] <= (s + t[i]) * (c[que[f + 1]] - c[que[f]])) ++f;

        int k = que[f];
        dp[i] = min(dp[i], dp[k] + t[i] * (c[i] - c[k]) + s * (c[n] - c[k]));

        while (f < r && (dp[i] - dp[que[r]]) * (c[que[r]] - c[que[r - 1]]) <= (dp[que[r]] - dp[que[r - 1]]) * (c[i] - c[que[r]])) --r; 
        que[++r] = i;
    }
    printf("%d\n", dp[n]);

    return 0;
}

猜你喜欢

转载自www.cnblogs.com/23forever/p/8881958.html