[LCA]Road

题目描述

Z 国是一个拥有N 个岛的国家。这N 个岛用N-1 条桥来连接,且任意两个岛之间都可以互达。
某商人听说Z 国是一个很富有的国家,所以他想到Z 国闯一闯。经过他仔细的观察,他发现某样商品特别受欢迎,而且由于各岛之间沟通联系不够多,所以这样物品在每个岛的价格可能都不同。
Task:商人开始在编号为x 的岛上,然后他要走到编号为y 的岛上。在这期间,他可以在x 岛y 的路径上买一件商品,和卖一件商品。,注意,仅能买一件和卖一件!显然你要计算商人从岛x 到岛y 最多能赚多少钱。

Input

输入第一行有一个整数N(1≤n≤50000),表示Z 国有N 个岛。
接下来有N 行,每行一个整数Ci(1≤Ci≤50000),第N+i 行的Ci 表示商品在岛i 的价
格。
再接下来有N-1 行,每行两个整数x,y(1≤x,y≤50000),表示岛x 和岛y 之间有一条
桥。
接下来有一个整数M,表示有M 个询问。
然后M 行,每行两个整数,x,y(1≤x,y≤50000),表示询问你,商人从岛x 到岛y 最多
能赚多少钱?

Output

对于每次询问,如果商人能赚到钱,则输出最多能赚多少钱。
如果不能赚钱,就输出0(你可以这样理解——亏本生意谁都不会做^_^)

Sample Input

4
1
2
3
4
1 2
1 4
2 3
3
1 3
3 1
1 4

Sample Output

2
0
3

Data Constraint

Hint

数据约定:
对于30%的数据, 1≤N,M≤100
对于60%的数据,1≤N,M≤1000
对于100%的数据,1≤N,M≤50000

分析

这题很容易想到LCA作为x,y的中间点
然后如何求最多赚的钱呢?
其实只要x和y分别从自己一个一个点地跑到LCA,途中发现最大值更新,如果最小值更新,最大值清零,同时用ans记录所有情况的最优值即可
(我就是没有用ans记录所有情况才拿了10分。。。)
巨尴尬

#include <iostream>
#include <cstdio>
#define rep(i,a,b) for (i=a;i<=b;i++)
using namespace std;
int n,m,big,ans;
int mx,mi,f;
int d[50001];
int p[50001][21];
int list[50001];
struct E
{
    int u,v,next;
}a[100001];
int cnt;
int b[50001];
void add(int u,int v)
{
    a[++cnt].u=u;a[cnt].v=v;a[cnt].next=list[u];list[u]=cnt;
}
void init()
{
    int i,x,y;
    scanf("%d",&n);
    x=0;
    rep(i,1,n)
    {
        scanf("%d",&b[i]);
        if (b[i]>x)
        {
            big=i;
            x=b[i];
        }
    }
    rep(i,1,n-1)
    {
        scanf("%d%d",&x,&y);
        add(x,y);
        add(y,x);
    }
}
void dfs(int x)
{
    int i;
    for (i=list[x];i;i=a[i].next)
    if (!d[a[i].v])
    {
        d[a[i].v]=d[x]+1;
        p[a[i].v][0]=x;
        dfs(a[i].v);
    }
}
void power()
{
    int i,j;
    rep(j,1,20)
    rep(i,1,n)
    p[i][j]=p[p[i][j-1]][j-1];
}
void doit()
{
    d[big]=1;
    dfs(big);
    power();
}
int lca(int x,int y)
{
    int a=x,b=y,i;
    if (d[a]<d[b]) swap(a,b);
    for (i=20;i>=0;i--)
    if (d[p[a][i]]>=d[b])
    a=p[a][i];
    if (a==b) return a;
    for (i=20;i>=0;i--)
    if (p[a][i]!=p[b][i])
    {
        a=p[a][i];
        b=p[b][i];
    }
    return p[a][0];
}
void dfs1(int x)
{
    if (b[x]<mi)
    {
        mi=b[x];
        mx=0;
    }
    mx=max(mx,b[x]);
    ans=max(ans,mx-mi);
    if (x==f) return;
    dfs1(p[x][0]);
}
void dfs2(int x)
{
    if (x==f) return;
    dfs2(p[x][0]);
    if (b[x]<mi)
    {
        mi=b[x];
        mx=0;
    }
    mx=max(mx,b[x]);
    ans=max(ans,mx-mi);
}
void print()
{
    int i,a,b;
    scanf("%d",&m);
    rep(i,1,m)
    {
        scanf("%d%d",&a,&b);
        ans=0;
        f=lca(a,b);
        mi=2147483647;
        dfs1(a);
        dfs2(b);
        printf("%d\n",ans);
    }
}
int main()
{
    freopen("road.in","r",stdin);
    freopen("road.out","w",stdout);
    init();
    doit();
    print();
}
# 加载必要包 library(poLCA) library(dplyr) library(tidyr) library(ggplot2) # 设置路径与变量 file_path <- "D:/SHUJU/car_and_ebike.csv" vars <- c("Driver.gender", "Driver.identity", "Passenger.car.state", "Weekend", "Road.condition.classification", "Crash.type", "Weather", "Visibility", "Lighting.condition", "Road.functional.class", "Rider.age", "Physical.separation.of.the.road", "Rider.gender", "Rider.hurt.part") # 读取并预处理数据 data <- read.csv(file_path) data <- data[vars] # 转换为从1开始的分类变量 data[] <- lapply(data, function(x) { x <- as.factor(x) x <- as.numeric(as.factor(x)) return(x) }) # 构建 LCA 公式 f <- as.formula(paste("cbind(", paste(vars, collapse = ","), ") ~ 1")) # 初始化存储指标 fit_stats <- data.frame() models <- list() N <- nrow(data) # 样本量,用于 CAIC # 拟合 1~10 类的模型 for (k in 1:10) { cat("拟合 LCA 模型,类别数 =", k, "\n") set.seed(123) lca_model <- poLCA(f, data, nclass = k, na.rm = FALSE, verbose = FALSE) models[[k]] <- lca_model # 熵R²计算 posterior <- lca_model$posterior entropy <- -rowSums(posterior * log(posterior + 1e-10)) max_entropy <- log(ncol(posterior)) entropy_r2 <- 1 - mean(entropy) / max_entropy # CAIC 计算 ll <- lca_model$llik num_params <- lca_model$npar caic <- -2 * ll + num_params * (log(N) + 1) # 存储结果 fit_stats <- rbind(fit_stats, data.frame( K = k, BIC = lca_model$bic, AIC = lca_model$aic, CAIC = caic, EntropyR2 = entropy_r2 )) } # ----------1:AIC、BIC、CAIC ---------- # 手动设置 y 轴范围,使图更“平缓” y_min <- min(fit_plot$Value) * 0.98 # 稍微留点空间 y_max <- max(fit_plot$Value) * 1.02 p1 <- ggplot(fit_plot, aes(x = K, y = Value, color = Metric)) + geom_line(size = 1.2) + geom_point(size = 2.5) + scale_x_continuous(breaks = 1:10) + labs(x = "Number of clusters", y = "Information criterion") + coord_cartesian(ylim = c(y_min, y_max)) + # 控制纵轴显示范围 theme_minimal(base_size = 14) + theme( plot.title = element_blank(), legend.position = c(0.82, 0.85), legend.background = element_rect(fill = alpha("white", 0.6), color = NA), legend.title = element_blank() ) # ---------- 图 2:熵 R² ---------- fit_stats_r2 <- fit_stats %>% filter(K > 1) p2 <- ggplot(fit_stats_r2, aes(x = K, y = EntropyR2)) + geom_line(color = "#1f77b4", size = 1.2) + geom_point(color = "#1f77b4", size = 2.5) + scale_x_continuous(breaks = 2:10) + ylim(0, 1) + labs(x = "Number of clusters", y = "Entropy R²") + theme_minimal(base_size = 14) + theme( plot.title = element_blank() ) # 调整图形窗口大小(RStudio 中有效) options(repr.plot.width=10, repr.plot.height=5) # 显示图形 print(p1) print(p2) 这是我的代码,已经选出了最佳的k值,想要继续下一步的聚类,你可以帮我继续完善代码吗
最新发布
06-13
标题:国王的烦恼 C国由n个小岛组成,为了方便小岛之间联络,C国在小岛间建立了m,每连接小岛。两个小岛间可能存在多连接。然而,由于海水冲刷,有一些大面临着不能使用的危险。 如果两个小岛间的所有大都不能使用,则这两小岛就不能直接到达了。然而,只要这两小岛的居民能通过其他的或者其他的小岛互相到达,他们就会安然无事。但是,如果前一天两个小岛之间还有方法可以到达,后一天却不能到达了,居民们就会一起抗议。 现在C国的国王已经知道了每能使用的天数,超过这个天数就不能使用了。现在他想知道居民们会有多少天进行抗议。 【输入格式】 输入的第一行包含两个整数n, m,分别表示小岛的个数和的数量。 接下来m行,每行三个整数a, b, t,分别表示该连接a号和b号两个小岛,能使用t天。小岛的编号从1开始递增。 【输出格式】 输出一个整数,表示居民们会抗议的天数。 【样例输入】 4 4 1 2 2 1 3 2 2 3 1 3 4 3 【样例输出】 2 【样例说明】 第一天后2和3之间的不能使用,不影响。 第二天后1和2之间,以及1和3之间的不能使用,居民们会抗议。 第三天后3和4之间的不能使用,居民们会抗议。 【数据规模与约定】 对于30%的数据,1<=n<=20,1<=m<=100; 对于50%的数据,1<=n<=500,1<=m<=10000; 对于100%的数据,1<=n<=10000,1<=m<=100000,1<=a, b<=n, 1<=t<=100000。 【资源约定】 峰值内存消耗 < 64M CPU消耗 < 3000ms 请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。 所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。 注意: main函数需要返回0 注意: 只使用ANSI C/ANSI C++ 标准,不要调用依赖于编译环境或操作系统的特殊函数。 注意: 所有依赖的函数必须明确地在源文件中 #include , 不能通过工程设置而省略常用头文件。 提交时,注意选择所期望的编译器类型。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值