D. Odd Mineral Resource

7 篇文章 0 订阅
5 篇文章 0 订阅

由于是统计树上某个区间的值,因此就是树上莫队了。

 

套个树上莫队的模板先。。。

对树上的区间进行排序,然后更新的时候判断一下更新的节点是奇还是偶,放进cnt数组里面。然后问题来了。

查询的是对cnt数组的一个区间进行查询,那么这里就需要用到树状数组去二分了。

这样在修改的时候就多了一个log,这样就T了。

 

所以不能对修改做任何扩展,只能修改查询部分。

继续使用分块思想。对cnt数组去分组。然后查询的时候一组一组去查询,如果组内有数据,就直接暴力返回结果。

一共有sqrt(n)个组,组内查询时间sqrt(n),那么总时间就是sqrt(n)+sqrt(n)了。

这样总时间也是q*sqrt(n)了。

 

int block_size;

struct query{
	int l,r,id;
	int u,v;
	int block;
	int r_block;
	bool operator<(const query &q) const{
		if(block != q.block) return block<q.block;
		return r_block<q.r_block;
	}
};

vector<int> g[N];
stack<int> st;
int blk,idx;
int block_num[N];
int sz[N],hs[N],dp[N],dfn[N],fa[N],top[N];
int ans[N],sum[N],num[N];
int c[N];
int n;

void dfs1(int t, int f){
	sz[t] = 1;
	fa[t] = f;
	hs[t] = 0;
	dp[t] = dp[f]+1;
	dfn[t] = idx++;
	st.push(t);
	int ss = st.size();
	for(int u:g[t]){
		if(u==f)continue;
		dfs1(u,t);
		sz[t] += sz[u];
		if(sz[u] > sz[hs[t]]) hs[t] = u;
		if(st.size() - ss >=block_size){
			while(st.size() >ss){
				block_num[st.top()]=blk;
				st.pop();
			}
			blk++;
		}
	}
	if(t==1){
		while(!st.empty()){
			block_num[st.top()]=blk;
			st.pop();
		}
		blk++;
	}
}

void dfs2(int t, int f){
	top[t] = f;
	if(!hs[t])return;
	dfs2(hs[t],f);
	for(int u : g[t]){
		if(u==fa[t] || u == hs[t])continue;
		dfs2(u,u);
	}
}

int lca(int u, int v){
	if(dp[u]<dp[v])swap(u,v);
	while(top[u]!=top[v]) {
		if(dp[top[u]] > dp[top[v]]) u = fa[top[u]];
		else v = fa[top[v]];
	}
	return dp[u]<dp[v]? u:v;
}

int get_ans(int l, int r){
	int bl = l/block_size;
	int br = r/block_size;
	for(int i = bl; i<=br; ++i){
		if(sum[i]==0)continue;
		int st = i * block_size;
		int ed = (i+1)*block_size-1;
		for(int i = max(st,l); i<=min(r,ed); ++i){
			if(num[i]) return i;
		}
	}
	return -1;
}

void change(int u){
	if(num[c[u]]==0){
		sum[c[u]/block_size]++;
	}
	else {
		sum[c[u]/block_size]--;
	}
 	num[c[u]]^=1;
}

int l = 0, r = 0;
void move(int u, int v){
	if(dp[u]<dp[v]) swap(u,v);
	while(dp[u]!=dp[v]){
		change(u);
		u = fa[u];
	}
	while(u!=v){
		change(u); change(v);
		u = fa[u]; v = fa[v];
	}
}

int main(){
	int Q;
	sf("%d%d",&n,&Q);
	block_size = pow(n,0.6);
	for(int i = 1; i <= n; ++i){
		sf("%d",&c[i]);
	}
	for(int i= 0; i<n-1; ++i){
		int u,v;
		sf("%d%d",&u,&v);
		g[u].pb(v);
		g[v].pb(u);
	}
	dfs1(1,1);
	dfs2(1,1);
	vector<query> q;
	map<pair<int,int>, vector<query>> tmp_ans;
	for(int i = 0; i < Q; ++i){
		query qy;
		sf("%d%d%d%d",&qy.u,&qy.v,&qy.l,&qy.r);
		if(dfn[qy.u]>dfn[qy.v]){
			swap(qy.u,qy.v);
		}
		qy.block = block_num[qy.u];
		qy.r_block = block_num[qy.v];
		qy.id = i;
		q.pb(qy);
	}

	sort(q.begin(), q.end());
	int u = 1, v = 1;
	change(lca(u,v));
	l = 0, r = 0;
	deque<int> cq;
	for(int i = 0; i < q.size();++i){
		int f = lca(u,v);
		change(f);
		if(u!=q[i].u){
			move(u,q[i].u);
			u = q[i].u;
		}
		if(v!=q[i].v){
			move(v,q[i].v);
			v = q[i].v;
		}
		f = lca(u,v);
		change(f);
		ans[q[i].id] = get_ans(q[i].l, q[i].r);
	}

	for(int i = 0; i < q.size();++i){
		printf("%d\n",ans[i]);
	}
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
代码下载:完整代码,可直接运行 ;运行版本:2022a或2019b或2014a;若运行有问题,可私信博主; **仿真咨询 1 各类智能优化算法改进及应用** 生产调度、经济调度、装配线调度、充电优化、车间调度、发车优化、水库调度、三维装箱、物流选址、货位优化、公交排班优化、充电桩布局优化、车间布局优化、集装箱船配载优化、水泵组合优化、解医疗资源分配优化、设施布局优化、可视域基站和无人机选址优化 **2 机器学习和深度学习方面** 卷积神经网络(CNN)、LSTM、支持向量机(SVM)、最小二乘支持向量机(LSSVM)、极限学习机(ELM)、核极限学习机(KELM)、BP、RBF、宽度学习、DBN、RF、RBF、DELM、XGBOOST、TCN实现风电预测、光伏预测、电池寿命预测、辐射源识别、交通流预测、负荷预测、股价预测、PM2.5浓度预测、电池健康状态预测、水体光学参数反演、NLOS信号识别、地铁停车精准预测、变压器故障诊断 **3 图像处理方面** 图像识别、图像分割、图像检测、图像隐藏、图像配准、图像拼接、图像融合、图像增强、图像压缩感知 **4 路径规划方面** 旅行商问题(TSP)、车辆路径问题(VRP、MVRP、CVRP、VRPTW等)、无人机三维路径规划、无人机协同、无人机编队、机器人路径规划、栅格地图路径规划、多式联运运输问题、车辆协同无人机路径规划、天线线性阵列分布优化、车间布局优化 **5 无人机应用方面** 无人机路径规划、无人机控制、无人机编队、无人机协同、无人机任务分配 **6 无线传感器定位及布局方面** 传感器部署优化、通信协议优化、路由优化、目标定位优化、Dv-Hop定位优化、Leach协议优化、WSN覆盖优化、组播优化、RSSI定位优化 **7 信号处理方面** 信号识别、信号加密、信号去噪、信号增强、雷达信号处理、信号水印嵌入提取、肌电信号、脑电信号、信号配时优化 **8 电力系统方面** 微电网优化、无功优化、配电网重构、储能配置 **9 元胞自动机方面** 交通流 人群疏散 病毒扩散 晶体生长 **10 雷达方面** 卡尔曼滤波跟踪、航迹关联、航迹融合

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值