(权限题)NFLSoj #4: Grass Planting 题解

本文介绍了两种解决‘Grass Planting’问题的方法:一种是利用树剖(Tree剖)的裸解,另一种是使用nlogn复杂度的算法,通过在节点的修改和查询操作中结合深度优先搜索序(DFS序)和树状数组(BIT)来实现高效求解。

可以裸上树剖

也可以动一动脑子nlogn过:对于每一次修改在u,v上+1,在lca(u,v)上-2

对于每一次查询u,v,取depth较大的那个球子数和

用一下dfs序加一个BIT就可以了

#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#include <cstdlib>
#include <utility>
#include <cctype>
#include <algorithm>
#include <bitset>
#include <set>
#include <map>
#include <vector>
#include <queue>
#include <deque>
#include <stack>
#include <cmath>
#define LL long long
#define LB long double
#define x first
#define y second
#define Pair pair<int,int>
#define pb push_back
#define pf push_front
#define mp make_pair
#define LOWBIT(x) x & (-x)
using namespace std;

const int MOD=1e9+7;
const LL LINF=2e16;
const int INF=2e9;
const int magic=348;
const double eps=1e-10;

inline int getint()
{
	char ch;int res;bool f;
	while (!isdigit(ch=getchar()) && ch!='-') {}
	if (ch=='-') f=false,res=0; else f=true,res=ch-'0';
	while (isdigit(ch=getchar())) res=res*10+ch-'0';
	return f?res:-res;
}

int n,q,ind=0;
vector<int> v[100048];
int Left[100048],Right[100048];
int seq[100048],Pos[100048];
int depth[10048],anc[10048][21];
string type;

int c[100048];
inline void update(int x,int delta)
{
	while (x<=n)
	{
		c[x]+=delta;
		x+=LOWBIT(x);
	}
}
inline int query(int x)
{
	int res=0;
	while (x)
	{
		res+=c[x];
		x-=LOWBIT(x);
	}
	return res;
}
inline int calc(int left,int right)
{
	return query(right)-query(left-1);
}

void dfs(int cur,int father)
{
	int i,j,to;
	Left[cur]=++ind;seq[ind]=cur;Pos[cur]=ind;
	for (i=0;i<v[cur].size();i++)
	{
		to=v[cur][i];
		if (to!=father)
		{
			depth[to]=depth[cur]+1;
			anc[to][0]=cur;
			for (j=1;j<=20;j++) anc[to][j]=anc[anc[to][j-1]][j-1];
			dfs(to,cur);
		}
	}
	Right[cur]=ind;
}

int get_lca(int u,int v)
{
	int i;
	if (depth[u]<depth[v]) swap(u,v);
	for (i=20;i>=0;i--)
		if (depth[anc[u][i]]>=depth[v]) u=anc[u][i];
	if (u==v) return u;
	for (i=20;i>=0;i--)
		if (anc[u][i]!=anc[v][i])
		{
			u=anc[u][i];
			v=anc[v][i];
		}
	return anc[u][0];
}

int main ()
{
	int i,x,y,LCA;
	n=getint();q=getint();
	for (i=1;i<=n-1;i++)
	{
		x=getint();y=getint();
		v[x].pb(y);v[y].pb(x);
	}
	depth[1]=1;dfs(1,0);
	for (i=1;i<=q;i++)
	{
		cin>>type;
		if (type[0]=='P')
		{
			x=getint();y=getint();
			LCA=get_lca(x,y);
			update(Pos[x],1);update(Pos[y],1);update(Pos[LCA],-2);
		}
		else
		{
			x=getint();y=getint();
			if (depth[x]<depth[y]) swap(x,y);
			printf("%d\n",calc(Left[x],Right[x]));
		}
	}
	return 0;
}


import pandas as pd import numpy as np import matplotlib.pyplot as plt from scipy import stats import warnings warnings.filterwarnings(&#39;ignore&#39;) # 设置中文字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 用来正常显示中文标签 plt.rcParams[&#39;axes.unicode_minus&#39;] = False # 用来正常显示负号 # 1. 读取数据 print("正在读取数据...") try: # 读取附件1 attachment1 = pd.read_excel(r"D:\比赛\建模\C\附件1.xlsx") # 读取附件2 attachment2_sheets = pd.read_excel(r"D:\比赛\建模\C\附件2.xlsx", sheet_name=None) planting_data = attachment2_sheets[&#39;种植数据&#39;] # 种植数据表 related_data = attachment2_sheets[&#39;相关数据&#39;] # 相关数据表 print("数据读取成功!") except Exception as e: print(f"读取数据时出错: {e}") exit() # 2. 数据探索 print("\n数据探索:") print("附件1 形状:", attachment1.shape) print("种植数据 形状:", planting_data.shape) print("相关数据 形状:", related_data.shape) print("\n附件1 前5行:") print(attachment1.head()) print("\n种植数据 前5行:") print(planting_data.head()) print("\n相关数据 前5行:") print(related_data.head()) # 3. 缺失值处理 print("\n缺失值检查:") print("附件1 缺失值:\n", attachment1.isnull().sum()) print("种植数据 缺失值:\n", planting_data.isnull().sum()) print("相关数据 缺失值:\n", related_data.isnull().sum()) # 数据中没有缺失值,无需处理 # 4. 异常值检测 (使用IQR方法) print("\n异常值检测:") def detect_outliers_iqr(data, column): Q1 = data[column].quantile(0.25) Q3 = data[column].quantile(0.75) IQR = Q3 - Q1 lower_bound = Q1 - 1.5 * IQR upper_bound = Q3 + 1.5 * IQR outliers = data[(data[column] < lower_bound) | (data[column] > upper_bound)] return outliers, lower_bound, upper_bound # 检测附件1中的地块面积异常值 outliers_area, lb_area, ub_area = detect_outliers_iqr(attachment1, &#39;地块面积&#39;) print(f"地块面积异常值数量: {len(outliers_area)}") print(f"地块面积异常值范围: [{lb_area}, {ub_area}]") # 检测种植数据中的种植面积异常值 outliers_planting, lb_planting, ub_planting = detect_outliers_iqr(planting_data, &#39;种植面积&#39;) print(f"种植面积异常值数量: {len(outliers_planting)}") print(f"种植面积异常值范围: [{lb_planting}, {ub_planting}]") # 检测相关数据中的亩产量异常值 outliers_yield, lb_yield, ub_yield = detect_outliers_iqr(related_data, &#39;亩产量&#39;) print(f"亩产量异常值数量: {len(outliers_yield)}") print(f"亩产量异常值范围: [{lb_yield}, {ub_yield}]") # 检测相关数据中的种植成本异常值 outliers_cost, lb_cost, ub_cost = detect_outliers_iqr(related_data, &#39;种植成本&#39;) print(f"种植成本异常值数量: {len(outliers_cost)}") print(f"种植成本异常值范围: [{lb_cost}, {ub_cost}]") # 绘制箱线图检查异常值 fig, axes = plt.subplots(2, 2, figsize=(12, 10)) # 地块面积箱线图 attachment1.boxplot(column=&#39;地块面积&#39;, ax=axes[0, 0]) axes[0, 0].set_title(&#39;地块面积分布&#39;) # 种植面积箱线图 planting_data.boxplot(column=&#39;种植面积&#39;, ax=axes[0, 1]) axes[0, 1].set_title(&#39;种植面积分布&#39;) # 亩产量箱线图 related_data.boxplot(column=&#39;亩产量&#39;, ax=axes[1, 0]) axes[1, 0].set_title(&#39;亩产量分布&#39;) # 种植成本箱线图 related_data.boxplot(column=&#39;种植成本&#39;, ax=axes[1, 1]) axes[1, 1].set_title(&#39;种植成本分布&#39;) plt.tight_layout() plt.savefig(&#39;异常值检测箱线图.png&#39;) plt.show() print("\n异常值处理: 所有异常值在业务背景下合理,保留不处理") # 5. 数据转换处理 (标准化) print("\n数据标准化处理:") # 选择需要标准化的数值列 numeric_cols = [&#39;地块面积&#39;, &#39;种植面积&#39;, &#39;亩产量&#39;, &#39;种植成本&#39;] # 计算均值和标准差 means = {} stds = {} for col in numeric_cols: if col in attachment1.columns: means[col] = attachment1[col].mean() stds[col] = attachment1[col].std() elif col in planting_data.columns: means[col] = planting_data[col].mean() stds[col] = planting_data[col].std() elif col in related_data.columns: means[col] = related_data[col].mean() stds[col] = related_data[col].std() print("均值:", means) print("标准差:", stds) # 标准化函数 def standardize_data(df, col, mean, std): if col in df.columns: df[f&#39;z_{col}&#39;] = (df[col] - mean) / std return df # 应用标准化 attachment1 = standardize_data(attachment1, &#39;地块面积&#39;, means[&#39;地块面积&#39;], stds[&#39;地块面积&#39;]) planting_data = standardize_data(planting_data, &#39;种植面积&#39;, means[&#39;种植面积&#39;], stds[&#39;种植面积&#39;]) related_data = standardize_data(related_data, &#39;亩产量&#39;, means[&#39;亩产量&#39;], stds[&#39;亩产量&#39;]) related_data = standardize_data(related_data, &#39;种植成本&#39;, means[&#39;种植成本&#39;], stds[&#39;种植成本&#39;]) print("标准化完成!") # 6. 数据补充 print("\n数据补充:") # 补充天气数据 (基于假设) months = list(range(1, 13)) temperature = [5, 8, 15, 20, 25, 28, 30, 28, 23, 18, 12, 7] # 月平均温度(°C) rainfall = [10, 15, 25, 40, 60, 100, 150, 120, 80, 50, 30, 15] # 月平均降雨量(mm) weather_data = pd.DataFrame({ &#39;月份&#39;: months, &#39;平均温度&#39;: temperature, &#39;降雨量&#39;: rainfall }) print("补充的天气数据:") print(weather_data.head()) # 补充销售单价均值 (使用范围的中值) if &#39;销售单价&#39; in related_data.columns: # 提取销售单价范围并计算中值 def extract_price_range(price_str): if isinstance(price_str, str) and &#39;-&#39; in price_str: parts = price_str.split(&#39;-&#39;) if len(parts) == 2: try: lower = float(parts[0]) upper = float(parts[1]) return (lower + upper) / 2 except: return np.nan return np.nan related_data[&#39;销售单价均值&#39;] = related_data[&#39;销售单价&#39;].apply(extract_price_range) print("销售单价均值计算完成!") # 7. 保存预处理后的数据 print("\n保存预处理后的数据...") save_path = r"D:\比赛\建模\C\\" # 使用与附件相同的目录 attachment1.to_csv(save_path + &#39;预处理后_附件1.csv&#39;, index=False, encoding=&#39;utf-8-sig&#39;) planting_data.to_csv(save_path + &#39;预处理后_种植数据.csv&#39;, index=False, encoding=&#39;utf-8-sig&#39;) related_data.to_csv(save_path + &#39;预处理后_相关数据.csv&#39;, index=False, encoding=&#39;utf-8-sig&#39;) weather_data.to_csv(save_path + &#39;补充_天气数据.csv&#39;, index=False, encoding=&#39;utf-8-sig&#39;) print(f"预处理完成! 数据已保存到 {save_path} 目录")修改我的代码报错原因是NameError: name &#39;planting_data&#39; is not defined
最新发布
08-24
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值