洛谷P4719 【模板】动态dp(ddp LCT)

本文深入探讨了一种动态DP算法的实现细节,通过具体题目解析,展示了如何利用动态规划解决复杂问题。文章提供了完整的代码示例,包括数据结构定义、状态转移方程及优化技巧,适合对算法有深入了解需求的读者。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意

题目链接

Sol

动态dp板子题。有些细节还没搞懂,待我研究明白后再补题解。。。

#include<bits/stdc++.h>
#define LL long long 
using namespace std;
const int MAXN = 1e5 + 10, INF = INT_MAX;
template<typename A, typename B> inline bool chmax(A &x, B y) {
    return x < y ? x = y, 1 : 0;
}
inline int read() {
    char c = getchar(); int x = 0, f = 1;
    while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
    while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return x * f;
}
int N, M, a[MAXN], f[MAXN][2];
struct Ma {
    LL m[3][3];
    Ma() {
        memset(m, -0x3f, sizeof(m));
    }
    Ma operator * (const Ma &rhs) const {
        Ma ans;
        for(int i = 1; i <= 2; i++)
            for(int j = 1; j <= 2; j++)
                for(int k = 1; k <= 2; k++)
                    chmax(ans.m[i][j], m[i][k] + rhs.m[k][j]);
        return ans;
    }
}val[MAXN], sum[MAXN];
vector<int> v[MAXN];
int ch[MAXN][2], fa[MAXN];
#define ls(x) ch[x][0]
#define rs(x) ch[x][1]
void update(int k) {
    sum[k] = val[k];
    if(rs(k)) sum[k] = sum[k] * sum[rs(k)];
    if(ls(k)) sum[k] = sum[ls(k)] * sum[k];
}
bool ident(int x) {
    return rs(fa[x]) == x;
}
bool isroot(int x) {
    return ls(fa[x]) != x && rs(fa[x]) != x;
}
void connect(int x, int _fa, int tag) {
    fa[x] = _fa;
    ch[_fa][tag] = x;
}
void rotate(int x) {
    int y = fa[x], r = fa[y], yson = ident(x), rson = ident(y);
    int b = ch[x][yson ^ 1];
    fa[x] = r;
    if(!isroot(y)) connect(x, r, rson);
    connect(b, y, yson);
    connect(y, x, yson ^ 1);
    update(y); update(x);
}
void splay(int x) {
    for(int y = fa[x]; !isroot(x); rotate(x), y = fa[x])
        if(!isroot(y))
            rotate(ident(y) == ident(x) ? y : x);
}
void access(int x) {
    for(int y = 0; x; x = fa[y = x]) {
        splay(x);
        if(rs(x)) {
            val[x].m[1][1] += max(sum[rs(x)].m[1][1], sum[rs(x)].m[2][1]);
            val[x].m[2][1] += sum[rs(x)].m[1][1];
        }
        if(y) {
            val[x].m[1][1] -= max(sum[y].m[1][1], sum[y].m[2][1]);
            val[x].m[2][1] -= sum[y].m[1][1];
        }
        val[x].m[1][2] = val[x].m[1][1];
        rs(x) = y;
        update(x);
    }
}
int Modify(int p, int v) {
    access(p); splay(p);
    val[p].m[2][1] -= a[p] - v; 
    update(p);
    a[p] = v;
    splay(1);
    return max(sum[1].m[1][1], sum[1].m[2][1]);
}
void dfs(int x, int _fa) {
    fa[x] = _fa;
    f[x][1] = a[x];
    for(auto &to : v[x]) {
        if(to == _fa) continue;
        dfs(to, x);
        f[x][0] += max(f[to][0], f[to][1]);
        f[x][1] += f[to][0];
    }
    val[x].m[1][1] = f[x][0]; val[x].m[1][2] = f[x][0];
    val[x].m[2][1] = f[x][1]; val[x].m[2][2] = -INF;
    update(x);
//  sum[x] = val[x];
}
int main() {
    //freopen("a.in", "r", stdin);
    N = read(); M = read();
    for(int i = 1; i <= N; i++) a[i] = read();
    for(int i = 1; i < N; i++) {
        int x = read(), y = read();
        v[x].push_back(y);
        v[y].push_back(x);
    }
    dfs(1, 0);
    while(M--) {
        int x = read(), y = read();
        printf("%d\n", Modify(x, y));
    }
    return 0;
}

转载于:https://www.cnblogs.com/zwfymqz/p/10425674.html

### 数据并行分布式数据并行的区别 在PyTorch中,`DataParallel`(简称DP)和`DistributedDataParallel`(简称DDP)是两种用于多GPU训练的技术。以下是它们的主要区别: #### 架构设计 - `DataParallel`通过将输入数据分片到多个GPU上执行前向传播和反向传播来实现模型的并行化[^1]。然而,它存在一些局限性,比如无法很好地支持模型并行,并且可能由于频繁的数据传输而导致性能瓶颈。 - `DistributedDataParallel`则允许更灵活的设计,在单机或多机环境下都能高效运行。它可以结合模型并行一起工作,而`DataParallel`目前尚不支持这一点。 #### 性能表现 - 使用`DataParallel`时,所有的子模块都会被复制到不同的设备上,主进程负责收集梯度并将更新后的参数广播回各个副本。这种方法虽然易于设置,但在大规模场景下效率较低[^3]。 - 对比之下,`DistributedDataParallel`提供了更高的吞吐量以及更低延迟的优势。这是因为每个进程中只维护一份完整的网络结构实例,减少了不必要的内存占用和通信开销[^2]。 #### 实现难度 - 尽管`DataParallel`容易配置,但它并不能充分利用所有可用硬件资源;相比之下,尽管初始化过程稍微复杂一点,但推荐优先考虑采用`DistributedDataParallel`来进行高效的分布式计算任务处理。 下面是一个简单的代码示例展示如何分别使用这两种API: ```python import torch import torch.nn as nn from torch.utils.data.distributed import DistributedSampler from torch.nn.parallel import DistributedDataParallel as DDP class ExampleModel(nn.Module): def __init__(self): super().__init__() self.fc = nn.Linear(10, 1) def forward(self, x): return self.fc(x) def setup_dp(model): device_ids = list(range(torch.cuda.device_count())) dp_model = nn.DataParallel(model.to(device_ids[0]), device_ids=device_ids) return dp_model def setup_ddp(rank, world_size, model): torch.distributed.init_process_group( backend='nccl', init_method='env://', world_size=world_size, rank=rank ) ddp_model = DDP(model.to(rank), device_ids=[rank]) sampler = DistributedSampler(dataset) if isinstance(dataloader.sampler, SequentialSampler) else None return ddp_model, dataloader(sampler=sampler) ``` 上述脚本展示了基本框架下的差异之处——对于后者而言还需要额外完成诸如初始化进程组之类的准备工作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值