[CodeChef April Challenge 2014] FBCHEF

本文介绍了一种使用树状数组优化的算法,针对特定的操作进行高效处理。通过预先处理操作并利用可持久化技术,实现了一个整体二分搜索的解决方案。该方法能够有效处理大规模数据集中的节点更新和查询任务。

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

Description

给出一棵n个点的,以1为根的有根树,每个点有点权wi
q次操作,有两种操作:
1 A X:对于所有的点B,定义dis(A,B)为A到B路径上的边数,将B的权值减去⌊X2dis(A,B)⌋\lfloor {X\over {2^{dis(A,B)}}}\rfloor2dis(A,B)X
2 A:问以A为根的子树内,有多少个点的点权<=0
n,q,X<=10^5

Solution

先考虑修改在询问前的做法
设F[x][k]表示以x为根的子树内,到x距离为k的点的修改值
那么一次修改我们会修改F[A][0…16],F[father[A]][0…15],…
然后我们询问考虑直接问A的每个祖先B的F[B][dis(A,B)]
注意到这里可能会算重,于是我们F数组记得实际上是修改值的差分值
注意到点权只会减少,于是我们可以考虑求出所有点第一次变成非正的时间
这个东西可以直接套整体二分
考虑一次修改复杂度为O(log^2 A),询问复杂度为O(log A),于是我们可以预先把操作加入,然后可持久化一下,这样整体二分的时候就不用重新加入修改
因为我们不能在可持久化的数组上二分,我们可以直接维护一个指针扫一扫
整体二分的时候时间的流动是有序的,指针扫动的总次数为O(n log^2 A)
那么总复杂度就是O(n log^2 A)

Code

#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define rep(i,a) for(int i=lst[a];i;i=nxt[i])
#define pb(a) push_back(a)
#define mp(a,b) make_pair(a,b)
using namespace std;

typedef long long ll;

int read() {
	char ch;
	for(ch=getchar();ch<'0'||ch>'9';ch=getchar());
	int x=ch-'0';
	for(ch=getchar();ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
	return x;
}

void write(int x) {
	if (!x) {puts("0");return;}
	char ch[20];int tot=0;
	for(;x;x/=10) ch[++tot]=x%10+'0';
	fd(i,tot,1) putchar(ch[i]);
	puts("");
}

const int N=1e5+5,D=17;

int t[N<<1],nxt[N<<1],lst[N],l;
void add(int x,int y) {t[++l]=y;nxt[l]=lst[x];lst[x]=l;}

int n,q,w[N],dfn[N],tot,tm,qu,fir[N],sz[N],fa[N],dep[N];

struct Ask{int x,t;}ask[N];
struct Atk{int x,v;}atk[N];

int tr[N];
void I(int x) {for(;x<=n;x+=x&-x) tr[x]++;}
int Q(int x) {int ret=0;for(;x;x-=x&-x) ret+=tr[x];return ret;}

int ord[N];
bool cmp(int x,int y) {return fir[x]<fir[y];}

void dfs(int x,int y) {
	fa[x]=y;dfn[x]=++tot;sz[x]=1;dep[x]=dep[y]+1;
	rep(i,x) if (t[i]!=y) dfs(t[i],x),sz[x]+=sz[t[i]];
}

int id[N],pt[N][D],p1[N],p2[N],cnt;
vector<ll> f[N][D];
vector<int> tim[N][D];

void solve(int l,int r,int x,int y) {
	if (l==r) {fo(i,x,y) fir[id[i]]=l;return;}
	int mid=l+r>>1,t1=0,t2=0;
	fo(i,x,y) {
		ll c=0;
		for(int z=id[i],j=0;j<=16&&z;z=fa[z],j++) {
			if (tim[z][j].empty()) continue;
			int pos=pt[z][j];
			while (pos<tim[z][j].size()-1&&tim[z][j][pos+1]<=mid) pos++,cnt++;
			while (pos>=0&&tim[z][j][pos]>mid) pos--,cnt++;
			if (pos>=0) c+=f[z][j][pos];
			pt[z][j]=max(pos,0);
		}
		if (c>=w[id[i]]) p1[++t1]=id[i];
		else p2[++t2]=id[i];
	}
	fo(i,1,t1) id[x+i-1]=p1[i];
	fo(i,1,t2) id[x+t1+i-1]=p2[i];
	solve(l,mid,x,x+t1-1);solve(mid+1,r,x+t1,y);
}

int main() {
	freopen("pang.in","r",stdin);
	freopen("pang.out","w",stdout);
	n=read();
	fo(i,1,n) w[i]=read();
	fo(i,1,n-1) {
		int x=read(),y=read();
		add(x,y);add(y,x);
	}
	q=read();dfs(1,0);
	tm=qu=0;
	fo(i,1,q) {
		int opt=read(),x=read();
		if (opt==1) atk[++tm].x=x,atk[tm].v=read();
		if (opt==2) ask[++qu].x=x,ask[qu].t=tm;
	}
	fo(i,1,tm) {
		int x=atk[i].x,v=atk[i].v;
		for(int j=0;j<=16&&x;j++,x=fa[x]) {
			fo(k,0,16-j) {
				ll tmp=(v>>j+k);
				if (fa[x]) tmp-=v>>j+k+2;
				if (!f[x][k].empty()) tmp+=f[x][k][f[x][k].size()-1];
				f[x][k].pb(tmp);tim[x][k].pb(i);
			}
		}
	}
	fo(i,1,n) id[i]=i;solve(1,tm+1,1,n);
	fo(i,1,n) ord[i]=i;sort(ord+1,ord+n+1,cmp);
	int j=0;
	fo(i,1,qu) {
		while (j<n&&fir[ord[j+1]]<=ask[i].t) I(dfn[ord[++j]]);
		write(Q(dfn[ask[i].x]+sz[ask[i].x]-1)-Q(dfn[ask[i].x]-1));
	}
	return 0;
}
内容概要:本文介绍了基于SMA-BP黏菌优化算法优化反向传播神经网络(BP)进行多变量回归预测的项目实例。项目旨在通过SMA优化BP神经网络的权重和阈值,解决BP神经网络易陷入局部最优、收敛速度慢及参数调优困难等问题。SMA算法模拟黏菌寻找食物的行为,具备优秀的全局搜索能力,能有效提高模型的预测准确性和训练效率。项目涵盖了数据预处理、模型设计、算法实现、性能验证等环节,适用于多变量非线性数据的建模和预测。; 适合人群:具备一定机器学习基础,特别是对神经网络和优化算法有一定了解的研发人员、数据科学家和研究人员。; 使用场景及目标:① 提升多变量回归模型的预测准确性,特别是在工业过程控制、金融风险管理等领域;② 加速神经网络训练过程,减少迭代数和训练时间;③ 提高模型的稳定性和泛化能力,确保模型在不同数据集上均能保持良好表现;④ 推动智能优化算法与深度学习的融合创新,促进多领域复杂数据分析能力的提升。; 其他说明:项目采用Python实现,包含详细的代码示例和注释,便于理解和二开发。模型架构由数据预处理模块、基于SMA优化的BP神经网络训练模块以及模型预测与评估模块组成,各模块接口清晰,便于扩展和维护。此外,项目还提供了多种评价指标和可视化分析方法,确保实验结果科学可信。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值