【codechef】Ancient Berland Roads(线段树)

本文深入探讨了大数据与AI技术在音视频领域的实际应用,包括图像处理、AR特效、音视频直播流媒体等方面的技术创新与实践案例。

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

题目描述

在古老的宝兰国有 N 座城市和 M 条双向道路。随着时间的流逝,一些道路渐渐变得破旧,最后因为损坏而无法使用,而从来没有人维修这些道路。作为古宝兰国历史的热爱者,你想要做一个小小的研究。为此,你想要写一个程序来处理以下的操作:

• D K,代表输入中的第 K 条道路损坏了。道路从 1 开始编号;

• P A B,代表编号为 A 的城市的人口数变为了 B。

我们称一些城市构成的集合为一个区域,当且仅当对于集合中的任意两座城市,都可以通过没有损坏的道路,仅经过集合中的城市互相到达。区域的人口数即为集合中所有城市的人口数之和。

给定初始的道路、人口数,以及 M 个操作。你的任务就是,在每次询问后输出人口数最大的区域中有多少个城市。

输入格式

输入数据的第一行包含三个整数 N、M 和 Q,分别代表城市数、道路数和操作数。接下来一行包含 N 个整数 P1, P2, . . . , PN,以空格隔开,代表每个城市的人口数。接下来 M 行,每行包含两个整数 Xj 和 Yj,代表编号为 Xj 和 Yj 之间有一条双向道路。接下来 Q 行,每行包含一个操作,格式如题目描述中所述。

输出格式

输出 Q 行,依次代表每次操作后人口数最多的区域的大小。


并查集。既然它是删边那我就反过来倒着加边。30分。(树状数组说好的logn复杂度?但求区间最值好像不止这点。。。

数列每次修改一个数值求最大值?看了大神代码果然用优先队列过的(然而并不理解为什么可以用while过滤。。。

然后注意一下以后在codechef上提交都用lld,不然会WA

#include<iostream>  
#include<algorithm>  
#include<string>  
#include<map>//ll dx[4]={0,0,-1,1};ll dy[4]={-1,1,0,0};  
#include<set>//  
#include<vector>  
#include<cmath>  
#include<stack>  
#include<string.h>  
#include<stdlib.h>  
#include<cstdio>   
#define ll long long
#define lowbit(x) (x) & (-x)
using namespace std;
map<char,int> r[27];
struct node{
	int a,b,c;
}x[500005];
struct node2{
	char a;
	int b,c,d;
}y[500005];
int fa[500005];
int n,m,q;
int find(int v){  
    if (fa[v] == v)  
        return v;  
    else  
        return fa[v]=find(fa[v]);  
}  
int g[500005];
int c2[500010],w[500005];
void update2(int ii,int val){ //修改点       
    w[ii]=val;  
    for(int i=ii; i<=n+5; i+=lowbit(i)){       
        if(val>c2[i])  
            c2[i]=val;  
        else  
            break;  
    }        
}        
int query(int l, int r){  
    int s=w[r];//上边界  
    while (l!=r){  
        for(r-=1;r-lowbit(r)>=l;r-=lowbit(r)){    
            s=max(s,c2[r]);//注意计算区间,不要夸区间  
        }    
        s=max(s,w[r]);  //下边界  
    }  
    return s;  
}   
int main(){    
	scanf("%d%d%d",&n,&m,&q);
	for(int i=0;i<=n;++i){
		fa[i]=i;
	}
	for(int i=1;i<=n;++i){
		scanf("%d",&g[i]);
		update2(i,g[i]);
	}
	for(int i=1;i<=m;++i){
		scanf("%d%d",&x[i].a,&x[i].b);
		x[i].c=0;
	}
	for(int i=0;i<q;++i){
		getchar();
		scanf("%c",&y[i].a);
		if(y[i].a=='D'){
			scanf("%d",&y[i].b);
			x[y[i].b].c=1;
		}
		else{
			scanf("%d%d",&y[i].b,&y[i].c);
			int tmp=y[i].c;
			y[i].c=g[y[i].b];
			g[y[i].b]=tmp;
			update2(y[i].b,tmp);
		}
	}
	int maxx=0,ss=0;
	for(int i=1;i<=m;++i){
		if(x[i].c==1){
			maxx=max(w[x[i].a],maxx);
			maxx=max(w[x[i].b],maxx);
			continue;
		}
		int aa=find(x[i].a),bb=find(x[i].b);
		if(aa!=bb){
			fa[aa]=bb;
			update2(bb,w[bb]+w[aa]);
			update2(aa,0);
			if(w[bb]>maxx){
				maxx=w[bb];
			}
		}
	}
	for(int i=q-1;i>=0;--i){
		y[i].d=query(1,n);
		if(y[i].a=='D'){
			int p=y[i].b;
			int aa=find(x[p].a),bb=find(x[p].b);
			if(aa!=bb){
				fa[aa]=bb;
				update2(bb,w[bb]+w[aa]);
				update2(aa,0);
			}
		}
		else{
			int p=y[i].b;
			int aa=find(p);
			update2(aa,w[aa]+y[i].c-g[p]);
			g[p]=y[i].c;
		}	
	}
	for(int i=0;i<q;++i)
		printf("%d\n",y[i].d);
}  

【线段树版100分代码】

#include<iostream>  
#include<algorithm>  
#include<string>  
#include<map>//ll dx[4]={0,0,-1,1};ll dy[4]={-1,1,0,0};  
#include<set>//  
#include<vector>  
#include<cmath>  
#include<stack>  
#include<string.h>  
#include<stdlib.h>  
#include<cstdio>   
#define ll long long
#define MAXM 500005
#define lowbit(x) (x) & (-x)
using namespace std;
struct node{
	int a,b,c;
}x[500005];
struct node2{
	char a;
	int b;
	ll c,d;
}y[500005];
int fa[500005];
int n,m,q;
int find(int v){  
    if (fa[v] == v)  
        return v;  
    else  
        return fa[v]=find(fa[v]);  
}  
ll g[500005];
ll w[500005];
struct SegTree //求最值
{
	struct node
	{
		long long num, sum;
	}tree[MAXM << 2];
	int L, R;
	long long V;
	void pushDown(int u, int l, int r, int m)//向下更新节点(节省时间)
	{
		if (tree[u].num != 0)
		{
			node &lson = tree[u << 1], &rson = tree[u << 1 | 1];
			lson.num += tree[u].num;
			rson.num += tree[u].num;
			tree[u].sum += tree[u].num;
			tree[u].num = 0;
		}
	}

	void pushUp(int u) //【改】 
	{   
		tree[u].sum = max(tree[u << 1].sum + tree[u << 1].num, tree[u << 1 | 1].sum + tree[u << 1 | 1].num);
	}
	void built(int u, int l, int r)
	{
		tree[u].num = 0;
		if (l == r)
		{
			tree[u].sum = 0;
			return;
		}
		int mid = l + r >> 1;
		built(u << 1, l, mid);
		built(u << 1 | 1, mid + 1, r);
		pushUp(u);
	}

	void _add(int u, int l, int r)//区间或者点加值
	{
		int mid = l + r >> 1;
		if (L <= l&&r <= R)
		{
			tree[u].num += V; //【改,求和是V*(r-l+1)】 //【改=会错】 
			pushDown(u, l, r, mid);
			return;
		}
		pushDown(u, l, r, mid);
		if (L <= mid)
			_add(u << 1, l, mid);
		if (R>mid)
			_add(u << 1 | 1, mid + 1, r);
		pushUp(u);
	}

	long long _query(int u, int l, int r)
	{
		int mid = l + r >> 1;
		if (L <= l&&r <= R)
		{
			pushDown(u, l, r, mid);
			return tree[u].sum;
		}
		pushDown(u, l, r, mid);
		long long cnt = 0;
		if (L <= mid)
			cnt = max(cnt, _query(u << 1, l, mid)); //【改】 
		if (mid<R) 
			cnt = max(cnt, _query(u << 1 | 1, mid + 1, r)); //【改】 
		pushUp(u);
		return cnt;
	}

	void add(int l, int r, long long v)
	{
		L = l;
		R = r;
		V = v;
		_add(1, 1, n);
	}
	long long query(int l, int r)
	{
		if (l <= r)
		{
			L = l, R = r;
			return _query(1, 1, n);
		}
		else
			return 0;
	}
}A;
int main(){    
	scanf("%d%d%d",&n,&m,&q);
	for(int i=0;i<=n;++i){
		fa[i]=i;
	}
	for(int i=1;i<=n;++i){
		scanf("%lld",&g[i]);  //每个城市的人口数 
		w[i]=g[i];
		A.add(i,i,g[i]);
	}
	for(int i=1;i<=m;++i){
		scanf("%d%d",&x[i].a,&x[i].b);  //编号之间有一条双向道路 
	}
	for(int i=0;i<q;++i){
		getchar();
		scanf("%c",&y[i].a);
		if(y[i].a=='D'){
			scanf("%d",&y[i].b);  //第 K 条道路损坏了
			x[y[i].b].c=1;
		}
		else{
			scanf("%d%lld",&y[i].b,&y[i].c);  //编号为 A 的城市的人口数变为了 B
			ll tmp=y[i].c;
			A.add(y[i].b,y[i].b,tmp-g[y[i].b]);
			y[i].c=g[y[i].b];
			g[y[i].b]=tmp;
			w[y[i].b]=tmp;
		}
	}
	for(int i=1;i<=m;++i){
		if(x[i].c==1)
			continue;
		int aa=find(x[i].a),bb=find(x[i].b);
		if(aa!=bb){
			fa[aa]=bb;
			A.add(bb,bb,w[aa]);
			A.add(aa,aa,-w[aa]);
			w[bb]+=w[aa];
			w[aa]=0;
		}
	} 
	for(int i=q-1;i>=0;--i){
		y[i].d=A.query(1,n);
		if(y[i].a=='D'){
			int p=y[i].b;
			int aa=find(x[p].a),bb=find(x[p].b);
			if(aa!=bb){
				fa[aa]=bb;
				A.add(bb,bb,w[aa]);
				A.add(aa,aa,-w[aa]);
				w[bb]+=w[aa];
				w[aa]=0;
			}
		}
		else{
			int p=y[i].b;
			int aa=find(p);
			A.add(aa,aa,y[i].c-g[p]);
			w[aa]+=y[i].c-g[p];
			g[p]=y[i].c;
		}
	}
	for(int i=0;i<q;++i)
		printf("%lld\n",y[i].d);
	return 0;
}  

用set的方法:

每次要合并就先把set里面的a和b先删掉(用pair存,默认以first优先排序),再ab合并后把新的根节点和值重新存进去。

更改点:先把set里面的这个点删掉(搜根节点),重新计算点值后存入

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

typedef long long ll;

const int N = 5e5 + 5;

int type,q,u,v,m;
ll val[N];
pair < int ,int > edges[N];
int uf[N];
ll prev[N];
int good[N];
int a[N];
int b[N];
ll ans[N];
string cur[N];

set < pair < ll , int > , greater < pair < ll , int > > > DSU;



ll QUERY(){
    set < pair < ll , int > > :: iterator it = DSU.begin();
    return it->first;
}


int FIND(int u)
{
    if(uf[u]!=uf[uf[u]]){
        uf[u] = FIND(uf[u]);
    }
    return uf[u];
}


void UNION(int u , int v)
{
    int xx = FIND(u);
    int yy = FIND(v);
    if(xx==yy) return;
    DSU.erase(make_pair(val[xx],xx));
    DSU.erase(make_pair(val[yy],yy));
    uf[yy] = xx;
    val[xx] += val[yy];
    DSU.insert(make_pair(val[xx],xx));
}




int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    int t,n;
    cin >> n >> m >> q;
    for(int i = 1; i<=n; ++i){
        cin >> val[i];
        uf[i] = i;
    }
    for(int i = 1; i<=m; ++i){
        cin >> u >> v;
        edges[i] = make_pair(u,v);
        good[i] = true;
    }

    for(int i = 1; i<=q; ++i){
        cin >> cur[i];
        if(cur[i][0]=='D'){
            cin >> a[i];
            good[a[i]] = false;
        }
        else{
            cin >> a[i] >> b[i];
            prev[i] = val[a[i]];
            val[a[i]] = b[i];
        }
    }

    for(int i = 1; i<=n; ++i){
        DSU.insert(make_pair(1LL * val[i],i));
    }
    for(int i = 1; i<=m; ++i){
        if(good[i]){
            UNION(edges[i].first,edges[i].second);
        }
    }

    ans[q] = QUERY();
    for(int i = q; i > 0; --i){
        if(cur[i][0]=='D'){
            UNION(edges[a[i]].first,edges[a[i]].second);
        }
        else{
            int ind = a[i];
            int newval = b[i];
            int leader = FIND(ind);
            DSU.erase(make_pair(val[leader],leader));
            val[leader] -= newval;
            val[leader] += prev[i];
            DSU.insert(make_pair(val[leader],leader));
        }
        ans[i-1] = QUERY();
    }

    for(int i = 1; i<=q; ++i){
        cout << ans[i] << endl;
    }
    return 0;
}


标题基于SpringBoot+Vue的学生交流互助平台研究AI更换标题第1章引言介绍学生交流互助平台的研究背景、意义、现状、方法与创新点。1.1研究背景与意义分析学生交流互助平台在当前教育环境下的需求及其重要性。1.2国内外研究现状综述国内外在学生交流互助平台方面的研究进展与实践应用。1.3研究方法与创新点概述本研究采用的方法论、技术路线及预期的创新成果。第2章相关理论阐述SpringBoot与Vue框架的理论基础及在学生交流互助平台中的应用。2.1SpringBoot框架概述介绍SpringBoot框架的核心思想、特点及优势。2.2Vue框架概述阐述Vue框架的基本原理、组件化开发思想及与前端的交互机制。2.3SpringBoot与Vue的整合应用探讨SpringBoot与Vue在学生交流互助平台中的整合方式及优势。第3章平台需求分析深入分析学生交流互助平台的功能需求、非功能需求及用户体验要求。3.1功能需求分析详细阐述平台的各项功能需求,如用户管理、信息交流、互助学习等。3.2非功能需求分析对平台的性能、安全性、可扩展性等非功能需求进行分析。3.3用户体验要求从用户角度出发,提出平台在易用性、美观性等方面的要求。第4章平台设计与实现具体描述学生交流互助平台的架构设计、功能实现及前后端交互细节。4.1平台架构设计给出平台的整体架构设计,包括前后端分离、微服务架构等思想的应用。4.2功能模块实现详细阐述各个功能模块的实现过程,如用户登录注册、信息发布与查看、在线交流等。4.3前后端交互细节介绍前后端数据交互的方式、接口设计及数据传输过程中的安全问题。第5章平台测试与优化对平台进行全面的测试,发现并解决潜在问题,同时进行优化以提高性能。5.1测试环境与方案介绍测试环境的搭建及所采用的测试方案,包括单元测试、集成测试等。5.2测试结果分析对测试结果进行详细分析,找出问题的根源并
内容概要:本文详细介绍了一个基于灰狼优化算法(GWO)优化的卷积双向长短期记忆神经网络(CNN-BiLSTM)融合注意力机制的多变量多步时间序列预测项目。该项目旨在解决传统时序预测方法难以捕捉非线性、复杂时序依赖关系的问题,通过融合CNN的空间特征提取、BiLSTM的时序建模能力及注意力机制的动态权重调节能力,实现对多变量多步时间序列的精准预测。项目不仅涵盖了数据预处理、模型构建与训练、性能评估,还包括了GUI界面的设计与实现。此外,文章还讨论了模型的部署、应用领域及其未来改进方向。 适合人群:具备一定编程基础,特别是对深度学习、时间序列预测及优化算法有一定了解的研发人员数据科学家。 使用场景及目标:①用于智能电网负荷预测、金融市场多资产价格预测、环境气象多参数预报、智能制造设备状态监测与预测维护、交通流量预测与智慧交通管理、医疗健康多指标预测等领域;②提升多变量多步时间序列预测精度,优化资源调度风险管控;③实现自动化超参数优化,降低人工调参成本,提高模型训练效率;④增强模型对复杂时序数据特征的学习能力,促进智能决策支持应用。 阅读建议:此资源不仅提供了详细的代码实现模型架构解析,还深入探讨了模型优化实际应用中的挑战与解决方案。因此,在学习过程中,建议结合理论与实践,逐步理解各个模块的功能实现细节,并尝试在自己的项目中应用这些技术方法。同时,注意数据预处理的重要性,合理设置模型参数与网络结构,控制多步预测误差传播,防范过拟合,规划计算资源与训练时间,关注模型的可解释性透明度,以及持续更新与迭代模型,以适应数据分布的变化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值