2.9

这一次考试全是树!!!rank 20+(⊙﹏⊙)
树结构对我来说说还是有一定的问题的,而且这次考试中的暴力分也没有拿全(按道理说这一次的暴力分还是很多的,都没有打)
再一次用事实证明了,不会就要毫不犹豫的打暴力(搜索大法好啊qwq)
这一次的排名相较于上次下降很快,是因为专题的原因还是自身态度的原因应该认真的反省,下次加油!


这一次的题目是YWJ大神的,在此%一%
另,不要在意题目中的主角……

JesseLiu 的预算方案

这里写图片描述
这里写图片描述
这里写图片描述

10分……
先用主件更新附件,再用附件往回更新主件,答案存于f[m][0]

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#define L 100
#define LL 30000 + 10
using namespace std;

struct node {
    int w, v;
} a[L];
int m, n, x, y, z, f[LL][L];
vector <int> son[L];

inline void dfs(int p, int now) {
    for (int i = 0; i < son[now].size(); ++i) {
        int u = son[now][i];
        for (int j = 0; j <= p - a[u].w; ++j) f[j][u] = f[j][now];
        dfs(p - a[u].w, u);
        for (int j = a[u].w; j <= p; ++j) f[j][now] = max(f[j][now], f[j - a[u].w][u] + a[u].v);
    }
    return ;
}

int main() {
    freopen("budget.in","r",stdin);
    freopen("budget.out","w",stdout);
    scanf("%d %d", &m, &n);
    for (int i = 1; i <= n; ++i) {
        scanf("%d %d %d", &x, &y, &z);
        a[i].w = x, a[i].v = x * y;
        son[z].push_back(i);
    }
    dfs(m, 0);
    printf("%d\n", f[m][0]);
    return 0;
}

染色

这里写图片描述
这里写图片描述
这里写图片描述

注意对于每一个node设置3维变量,切记2维不够,考试WA在这里
我的代码中:dp[i][0]表示染色i所花费的总代价, dp[i][1]表示染i的儿子的总代价,dp[i][2]表示染i的父亲所花费的总代价–>故由题设:最后答案为min(dp[root][0], dp[root][1]),root为根节点,没有父亲
dp的转移方程为:
dp[i][0] = w[i] + min(dp[j][0], dp[j][2]) [j为i的所有子节点];
dp[i][1] = min(dp[i][1], dp[i][2] - min(dp[j][0], dp[j][1]) + dp[j][0])[dp[i][1]先赋值正无穷];
dp[i][2] += min(dp[j][0], dp[j][1])[即染了j的父亲i但没有染到j,需要染j或其儿子];
感觉自己有没有说的很懂的来着(⊙﹏⊙)

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define L 100000 + 10
#define inf 2147483640
using namespace std;

struct node{
    int nxt, to;
} e[L];
int n, x, num, y, z, ans, w[L], fa[L], cnt;
int dp[L][3], root, head[L];
bool vis[L];

inline void add(int a, int b) {
    e[++cnt].nxt = head[a], e[cnt].to = b, head[a] = cnt;
}

inline void dfs(int x) {
    dp[x][0] = w[x], dp[x][1] = inf;
    for (int u = head[x]; u; u = e[u].nxt) {
        int v = e[u].to;
        dfs(v);
        dp[x][0] += min(dp[v][0], dp[v][2]);
        dp[x][2] += min(dp[v][0], dp[v][1]);
    }
    for (int u = head[x]; u; u = e[u].nxt) {
        int v = e[u].to;
        dp[x][1] = min(dp[x][1], dp[x][2] - min(dp[v][1], dp[v][0]) + dp[v][0]);
    }
}

int main()
{
//<-------------------手动扩栈---------------------->
    int size = 32 << 20; // 256MB
    char *p = (char*)malloc(size) + size;
    __asm__("movl %0, %%esp\n" :: "r"(p));
//<----------------------------------------------->
    freopen("color.in", "r", stdin);
    freopen("color.out", "w", stdout);
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i) {
        scanf("%d %d %d", &x, &z, &num), w[x] = z;
        for (int i = 1; i <= num; ++i) scanf("%d", &y), add(x, y), fa[y] = x;
    }
    for (int i = 1; i <= n; ++i) if (!fa[i]) root = i;
    dfs(root);
    printf("%d\n", min(dp[root][0], dp[root][1]));
    return 0;
}

小学生

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

这是一道tarjan求强连通分量的题
第一遍dfs求强连通分量,对于没有标记的点即为”NO”输出所要求的点
然后进行tarjan操作详情参见图的强连通分量【还没有链接,明天再补】
将每一个强连通分量的代表元素所需要的代价记录进入ans输出即可

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <stack>
#define L 3000 + 10
#define inf 2147483640
using namespace std;

struct node {
    int nxt, to;
} a[20020 << 1];
int m, n, p, x, y, ans = 0, w[L], index[L], colour[L];
int cost[L], head[L], dfn[L], low[L], cnt, tot, num;
bool vis[L];
stack <int> point;

inline void add(int x, int y) {
    a[++cnt].nxt = head[x], a[cnt].to = y, head[x] = cnt;
}

inline void dfs(int u) {
    if (vis[u]) return ;
    vis[u] = 1;
    for (int i = head[u]; i; i = a[i].nxt) {
        int v = a[i].to;
        if (vis[v]) continue;
        dfs(v);
    }
}

inline void tarjan(int u) {
    dfn[u] = low[u] = ++num; point.push(u); vis[u] = 1;
    for (int i = head[u]; i; i = a[i].nxt) {
        int v = a[i].to;
        if (!dfn[v]) tarjan(v), low[u] = min(low[u], low[v]);
        else if (vis[v]) low[u] = min(low[u], dfn[v]);
    }
    if (low[u] == dfn[u]) {
        tot++;
        int temp;
        cost[tot] = inf;
        do {
            temp = point.top();
            vis[temp] = 0, colour[temp] = tot, point.pop();
            if (w[temp] > 0) cost[tot] = min(cost[tot], w[temp]);
        } while(temp != u);
        if (cost[tot] == inf) cost[tot] = 0;
    }
}

int main() {
    freopen("pupil.in", "r", stdin);
    freopen("pupil.out", "w", stdout);
    scanf("%d %d", &n, &p);
    for (int i = 1; i <= p; ++i) scanf("%d %d", &x, &y), w[x] = y;
    scanf("%d", &m);
    for (int i = 1; i <= m; ++i) scanf("%d %d", &x, &y), add(x, y);
    for (int i = 1; i <= n; ++i) 
        if (w[i]) dfs(i);
    for (int i = 1; i <= n; ++i)
        if (!vis[i]) {
            printf("NO\n%d", i); return 0;
        }
    memset(vis, 0, sizeof(vis));
    for (int i = 1; i <= n; ++i) if (!dfn[i]) tarjan(i);
    for (int i = 1; i <= n; ++i) 
        for (int u = head[i]; u; u = a[u].nxt) {
            int v = a[u].to;
            if (colour[i] != colour[v]) index[colour[v]]++;             
        }
    for (int i = 1; i <= tot; ++i) 
        if (!index[i]) ans += cost[i];
    printf("YES\n%d", ans);
    return 0;
}

简单数据结构练习

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

这道题是树链剖分
对于m1的操作即为链剖的板子
对于m2的操作采用离线处理,将所有的输入记录下来,然后对于进行m2操作之前的每一个点做求和操作进行记录,最后按照最大到小的顺序插入新的线段树中,进行求和操作和即为当前点的ans,记录入数组,最后统一输出即可
据说这一题还可以用主席树之类的,反正我不会,妥妥地接受了树链剖分

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define ls (x << 1)
#define rs (x << 1 | 1)
#define L 50000 + 10
using namespace std;

struct edge {
    int nxt, to;
} e[L << 1];
struct node {
    int pd, id, x, y, z;
} g[L << 2];
int n, a, b, cnt, head[L], fa[L], son[L], tp[L], ans[L];
int m, bj, dfn[L], sum[L], d[L], siz[L], num, tree[L << 2]; 

inline void add(int a, int b) {
    e[++cnt].nxt = head[a], e[cnt].to = b, head[a] = cnt;
}

inline void dfs1(int x, int dep) {
    d[x] = dep, siz[x] = 1;
    for (int u = head[x]; u; u = e[u].nxt) {
        int v = e[u].to;
        if (!d[v]) {
            dfs1(v, dep + 1), siz[x] += siz[v], fa[v] = x;
            if (siz[v] > siz[son[x]]) son[x] = v;
        }
    }
}

inline void dfs2(int x, int f) {
    dfn[x] = ++num, tp[x] = f;
    if (son[x]) dfs2(son[x], f);
    for (int u = head[x]; u; u = e[u].nxt) {
        int v = e[u].to;
        if (v != son[x] && v != fa[x]) dfs2(v, v);
    }
    sum[x] = num;
}

inline void updata (int x, int l, int r, int a, int v) {
    if (a == l && l == r) { tree[x] = v; return;}
    int mid = (l + r) >> 1;
    if (a <= mid) updata(ls, l, mid, a, v);
    else updata(rs, mid + 1, r, a, v);
    tree[x] = tree[ls] + tree[rs];
}

inline int query(int x, int l, int r, int a, int b) {
    if (a <= l && r <= b) return tree[x];
    int mid = (l + r) >> 1;
    if (b <= mid) return query(ls, l, mid, a, b);
    else if (a > mid) return query(rs, mid + 1, r, a, b);
    else return query(ls, l, mid, a, mid) + query(rs, mid + 1, r, mid + 1, b);
}

inline int lca(int a, int b) {
    int tot = 0;
    while (tp[a] != tp[b]) {
        if (d[tp[a]] < d[tp[b]]) swap(a, b);
        tot += query(1, 1, n, dfn[tp[a]], dfn[a]);
        a = fa[tp[a]];
    }
    if (d[a] > d[b]) swap(a, b);
    tot += query(1, 1, n, dfn[a], dfn[b]);
    return tot;
}

inline bool comp(node a, node b) {
    if (a.z == b.z) return a.pd < b.pd;
    return a.z < b.z;
}

int main() {
//  freopen("tree.in","r",stdin);
//  freopen("tree.out","w",stdout);
    scanf("%d", &n);
    for (int i = 1; i < n; ++i) scanf("%d %d", &a, &b), add(a, b), add(b, a);
    dfs1(1, 1), dfs2(1, 1);
    scanf("%d", &m);
    for (int i = 1; i <= m; ++i) {
        scanf("%d", &bj);
        if (bj == 1) scanf("%d %d", &a, &b), updata(1, 1, n, dfn[a], b);
        if (bj == 2) scanf("%d %d", &a, &b), printf("%d\n", lca(a, b));
        if (bj == 3) scanf("%d", &a), printf("%d\n", query(1, 1, n, dfn[a], sum[a]));
    }
    scanf("%d", &m);
    for (int i = 1; i <= m; ++i) {
        scanf("%d", &g[i].pd), g[i].id = i;
        if (g[i].pd == 1) scanf("%d %d %d", &g[i].x, &g[i].y, &g[i].z);
        if (g[i].pd == 2) scanf("%d %d", &g[i].x, &g[i].z);
    }
    for (int i = 1; i <= n; ++i) g[++m].pd = 0, g[m].x = dfn[i], g[m].z = query(1, 1, n, dfn[i], dfn[i]);
    memset(tree, 0, sizeof(tree));
    sort(g + 1, g + 1 + m, comp);
    for (int i = 1; i <= m; ++i) {
        if (g[i].pd == 0) updata(1, 1, n, g[i].x, 1);
        if (g[i].pd == 1) ans[g[i].id] = lca(g[i].x, g[i].y);
        if (g[i].pd == 2) ans[g[i].id] = query(1, 1, n, dfn[g[i].x], sum[g[i].x]);
    }
    for (int i = 1; i <= m - n; ++i) printf("%d\n", ans[i]);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值