CF980F 题解

CF980F

每一个点都指属于一个环,考虑对于每一个环进行计算答案。

考虑基环树的情况,我们会计算出其余的点,之后对于环上的点单独进行 D p Dp Dp

这边也是同理,找到每一个点属于的环,钦定一下每一个环的根。

因为计算距离需要使用换根 D p Dp Dp

我们考虑需要预处理写什么,也就是对于不同环之间的转移,然后对于同一个环内我们需要记录环根的答案。

对于不同环之间的转移,对于每一个点设 f 0 i f0_i f0i 表示向下,从所属环不同的点到当前环的最小距离。

然后对于环根还要特别记录一下 f 1 i f1_i f1i 表示考虑环上的情况。

因为环根才可以将之前的节点都考虑到。

之后设 f i = max ⁡ ( f 0 i , f 1 i ) f_i = \max(f0_i, f1_i) fi=max(f0i,f1i) 也就是向下走的答案。

之后考虑向上走,设 g i g_i gi 表示向上走的答案。

我们这个时候可以将 f 0 i = max ⁡ ( f 0 i , g i ) f0_i = \max(f0_i, g_i) f0i=max(f0i,gi) 方便处理。

可以从所属环不同的点进行转移,记录最大最次大值。

之后考虑整个环对于当前点进行转移,也就是 min ⁡ ( l , r ) \min(l, r) min(l,r) 左右两边,我们分别对其进行单调队列即可。


可能因为我代码实现问题,我的数组需要多开大几倍。

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

//#define Fread
//#define Getmod

#ifdef Fread
char buf[1 << 21], *iS, *iT;
#define gc() (iS == iT ? (iT = (iS = buf) + fread (buf, 1, 1 << 21, stdin), (iS == iT ? EOF : *iS ++)) : *iS ++)
#define getchar gc
#endif // Fread

template <typename T>
void r1(T &x) {
	x = 0;
	char c(getchar());
	int f(1);
	for(; c < '0' || c > '9'; c = getchar()) if(c == '-') f = -1;
	for(; '0' <= c && c <= '9';c = getchar()) x = (x * 10) + (c ^ 48);
	x *= f;
}

#ifdef Getmod
const int mod  = 1e9 + 7;
template <int mod>
struct typemod {
    int z;
    typemod(int a = 0) : z(a) {}
    inline int inc(int a,int b) const {return a += b - mod, a + ((a >> 31) & mod);}
    inline int dec(int a,int b) const {return a -= b, a + ((a >> 31) & mod);}
    inline int mul(int a,int b) const {return 1ll * a * b % mod;}
    typemod<mod> operator + (const typemod<mod> &x) const {return typemod(inc(z, x.z));}
    typemod<mod> operator - (const typemod<mod> &x) const {return typemod(dec(z, x.z));}
    typemod<mod> operator * (const typemod<mod> &x) const {return typemod(mul(z, x.z));}
    typemod<mod>& operator += (const typemod<mod> &x) {*this = *this + x; return *this;}
    typemod<mod>& operator -= (const typemod<mod> &x) {*this = *this - x; return *this;}
    typemod<mod>& operator *= (const typemod<mod> &x) {*this = *this * x; return *this;}
    int operator == (const typemod<mod> &x) const {return x.z == z;}
    int operator != (const typemod<mod> &x) const {return x.z != z;}
};
typedef typemod<mod> Tm;
#endif

template <typename T,typename... Args> inline void r1(T& t, Args&... args) {
    r1(t);  r1(args...);
}

//#define int long long
const int maxn = 2e6 + 5;
const int maxm = maxn << 1;

vector<int> vc[maxn];
void add(int u,int v) {
    vc[u].push_back(v);
}
int f[maxn], g[maxn], f0[maxn], f1[maxn];
int mx[maxn][2];
vector<int> cir[maxn];
int bel[maxn];
int n, m;


int vis[maxn], fa[maxn];

void dfs(int p,int pre) {
    vis[p] = 1, fa[p] = pre;
    for(auto v : vc[p]) {
        if(v == pre) continue;
        if(vis[v]) {
            if(bel[p]) continue;
            ++ m;
            for(int j = p; j != v; j = fa[j])
                bel[j] = m, cir[m].push_back(j);
            bel[v] = m, cir[m].push_back(v);
//            printf("m = %d\n", m);
            continue;
        }
        dfs(v, p);
    }
    if(!bel[p]) {
//            printf("m = %d\n", m);
        cir[++ m].push_back(p);
        bel[p] = m;
    }
}

void dpf(int p) {
    vis[p] = 1;
    for(auto v : vc[p]) {
        if(vis[v]) continue;
        dpf(v);
        if(bel[v] != bel[p]) {
            f0[p] = max(f0[p], f[v] + 1);
            if(!mx[p][0] || f[mx[p][0]] < f[v]) mx[p][1] = mx[p][0], mx[p][0] = v;
            else if(!mx[p][1] || f[mx[p][1]] < f[v]) mx[p][1] = v;
        }
    }
    int x = bel[p], sz = cir[x].size();
    if(p == cir[x][sz - 1]) {
        for(int i = 0; i < sz; ++ i) {
            int v = cir[x][i];
            f1[p] = max(f1[p], min(sz - i - 1, i + 1) + f[v]);
        }
    }// 这个是考虑向下的答案,每一个环的最后一个节点是有用的,之后其余的节点需要进行换根处理
    f[p] = max(f0[p], f1[p]);
}

struct Node {
    int val, id;
    Node(int a = 0,int b = 0) : val(a), id(b) {}
    int operator < (const Node &z) const {
        return val < z.val;
    }
    int operator <= (const Node &z) const {
        return val <= z.val;
    }
}q[maxn];

int hd, tl;

void dpg(int p) {
    vis[p] = 1; int pre = fa[p];
    int x = bel[p], sz = cir[x].size();
    if(pre && bel[pre] != bel[p]) {
        g[p] = max(g[p], g[pre] + 1);
        g[p] = max(g[p], f1[pre] + 1);
        if(mx[pre][0] == p) {
            if(mx[pre][1]) g[p] = max(g[p], f[mx[pre][1]] + 2);
        }
        else g[p] = max(g[p], f0[pre] + 1);
    }
    f0[p] = max(f0[p], g[p]);
    if(p == cir[x][sz - 1]) {
        hd = tl = 1;
        q[1] = Node(f0[cir[x][0]], 0);
        for(int i = 1; i <= sz / 2; ++ i) {
            while(hd <= tl && q[tl] <= f0[cir[x][i]] + i) -- tl;
            q[++ tl] = Node (f0[cir[x][i]] + i, i);
        }
        auto Max = [&] (int &s, const int &c) {
            return (s < c ? s = c : 0), void();
        };
        for(int i = 0; i < sz - 1; ++ i) { // 环根已经被计算过了
            if(q[hd].id == i) ++ hd;
            Max(g[cir[x][i]], q[hd].val - i);
            int nx = i + sz / 2 + 1;
            while(hd <= tl && q[tl] <= f0[cir[x][nx % sz]] + nx) -- tl;
            q[++ tl] = Node (f0[cir[x][nx % sz]] + nx, nx);
        }

        hd = tl = 1;
        q[1] = Node (f0[cir[x][sz / 2]] + sz / 2, sz / 2);
        for(int i = sz / 2 + 1; i < sz; ++ i) {
            while(hd <= tl && q[tl] <= f0[cir[x][i]] + sz - i) -- tl;
            q[++ tl] = Node (f0[cir[x][i]] + sz - i, i);
        }
        for(int i = 0; i < sz - 1; ++ i) {
            if(q[hd].id == sz / 2 + i) ++ hd;
            Max(g[cir[x][i]], q[hd].val + i);
            int nx = sz + i;
            while(hd <= tl && q[tl] <= f0[cir[x][nx % sz]] + sz - nx) -- tl;
            q[++ tl] = Node (f0[cir[x][nx % sz]] + sz - nx, nx);
        }
    }
    for(auto v : vc[p]) if(!vis[v]) dpg(v);
}

signed main() {
//    freopen("S.in", "r", stdin);
//    freopen("S.out", "w", stdout);
    int i, j;
    r1(n, m);
    for(i = 1; i <= m; ++ i) {
        int u, v;
        r1(u, v);
        add(u, v), add(v, u);
    }
    m = 0;
    dfs(1, 0);
    memset(vis, 0, sizeof(vis));
    dpf(1);
    memset(vis, 0, sizeof(vis));
    dpg(1);
    for(i = 1; i <= n; ++ i) printf("%d%c", max(f[i], g[i]), " \n"[i == n]);
	return 0;
}
内容概要:本文是一篇关于使用RandLANet模型对SensatUrban数据集进行点云语义分割的实战教程,系统介绍了从环境搭建、数据准备、模型训练与测试到精度评估的完整流程。文章详细说明了在Ubuntu系统下配置TensorFlow 2.2、CUDA及cuDNN等深度学习环境的方法,并指导用户下载和预处理SensatUrban数据集。随后,逐步讲解RandLANet代码的获取与运行方式,包括训练、测试命令的执行与参数含义,以及如何监控训练过程中的关键指标。最后,教程涵盖测试结果分析、向官方平台提交结果、解读评估报告及可视化效果等内容,并针对常见问题提供解决方案。; 适合人群:具备一定深度学习基础,熟悉Python编程和深度学习框架,从事计算机视觉或三维点云相关研究的学生、研究人员及工程师;适合希望动手实践点云语义分割项目的初学者与进阶者。; 使用场景及目标:①掌握RandLANet网络结构及其在点云语义分割任务中的应用;②学会完整部署一个点云分割项目,包括数据处理、模型训练、测试与性能评估;③为参与相关竞赛或科研项目提供技术支撑。; 阅读建议:建议读者结合提供的代码链接和密码访问完整资料,在本地或云端环境中边操作边学习,重点关注数据格式要求与训练参数设置,遇到问题时参考“常见问题与解决技巧”部分及时排查。
内容概要:本文详细介绍了三相异步电机SVPWM-DTC(空间矢量脉宽调制-直接转矩控制)的Simulink仿真实现方法,结合DTC响应快与SVPWM谐波小的优点,构建高性能电机控制系统。文章系统阐述了控制原理,包括定子磁链观测、转矩与磁链误差滞环比较、扇区判断及电压矢量选择,并通过SVPWM技术生成固定频率PWM信号,提升系统稳态性能。同时提供了完整的Simulink建模流程,涵盖电机本体、磁链观测器、误差比较、矢量选择、SVPWM调制、逆变器驱动等模块的搭建与参数设置,给出了仿真调试要点与预期结果,如电流正弦性、转矩响应快、磁链轨迹趋圆等,并提出了模型优化与扩展方向,如改进观测器、自适应滞环、弱磁控制和转速闭环等。; 适合人群:电气工程、自动化及相关专业本科生、研究生,从事电机控制算法开发的工程师,具备一定MATLAB/Simulink和电机控制理论基础的技术人员。; 使用场景及目标:①掌握SVPWM-DTC控制策略的核心原理与实现方式;②在Simulink中独立完成三相异步电机高性能控制系统的建模与仿真;③通过仿真验证控制算法有效性,为实际工程应用提供设计依据。; 阅读建议:学习过程中应结合文中提供的电机参数和模块配置逐步搭建模型,重点关注磁链观测、矢量选择表和SVPWM调制的实现细节,仿真时注意滞环宽度与开关频率的调试,建议配合MATLAB官方工具箱文档进行参数校准与结果分析。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值