【算法每日一练]-结构优化(保姆级教程 篇5 树状数组)POJ3067日本 #POJ3321苹果树 #POJ2352星星

news/2024/7/15 18:34:02 标签: 算法, 数据结构, c++, 深度优先, 图论

目录

今天知识点

求交点转化求逆序对,每次操作都维护一个y点的前缀和

树的变动转化成一维数组的变动,利用时间戳将节点转化成区间

先将y排序,然后每加入一个就点更新求一次前缀和

POJ3067:日本

思路:

POJ3321苹果树:

思路:

POJ2352:星星

思路:


        

        

POJ3067:日本

东海岸有n个城市,西海岸有m个城市,每个海岸的城市从北到南编号为1,2……,每条高速公路都是直线,连接东西海岸的城市。求公路的交叉点数

输入:
1
3 4 4
1 4
2 3
3 2
3 1

        
思路:

根据样例画出草图:按照1 4,2 3,3 1,3 2的顺序去画,很容易发现只要出现逆序对就会产生交点。

定义逆序对:(x1,y1)和(x2,y2)为逆序对,则等价于x1<x2且y1<y2。

所以在画2 3时候产生了一个逆序对,画3 1时候产生了2个逆序对,画 3 2时候也产生了两个逆序对。故最终5个交点。

所以这道题就是求逆序对数。

因为比如两边都同时大于或小于。我们先对x排序(若x相等,则y升序),然后按x的顺序检查每条边,统计y的前缀和,因为当前已经连了i条边,那么y的前缀和数就一定是非逆序对数。所以i减去y的前缀和就是逆序对数。

这道题就变成了每次增加一个元素就前一次对应的前缀和问题。因此我们只需要对每个点y维护一个关于y的前缀。每次操作后都要给对应点y加个1
        

#include <bits/stdc++.h>
using namespace std;
#define maxn 1010
#define maxk 1000010
#define lowbit(x) (x)&(-x)
typedef long long ll;
int c[maxn],kas,n,m,k;
struct edge{int x,y;}e[maxk];

bool cmp(edge a,edge b){
	return a.x<b.x||(a.x==b.x&&a.y<b.y);
}

void add(int i){//加1操作,参数省略
	while(i<=m){
		++c[i];
		i+=lowbit(i);
	}
}

int sum(int i){
	int s=0;
	while(i>0){
		s+=c[i];
		i-=lowbit(i);
	}
	return s;
}

int main(){
	int t;cin>>t;
	while(t--){
		memset(c,0,sizeof(c));//每个样例都要清空一次树状数组。
		scanf("%d%d%d",&n,&m,&k);
		for(int i=0;i<k;i++)
			scanf("%d%d",&e[i].x,&e[i].y);
			sort(e,e+k,cmp);//默认升序
			ll ans=0;
			for(int i=0;i<k;i++){
				ans+=i-sum(e[i].y);//累加逆序对
				add(e[i].y);//加入进去
			}
			printf("Test case %d: %lld\n",++kas,ans);
	}
}

        

        

POJ3321苹果树:

        
一个苹果树上有n个叉,通过分支连接,我们将叉从1到n进行编号,每个叉上最多只会有一个苹果,且苹果树上一开始长满了苹果。
卡卡可能会从树上摘一个苹果,树上的空叉可能又会长出新的苹果。
输入:
第一行n表示叉数。
以下n-1行是两个整数u和v表示之间有叉相连
以下m行表示m条消息
C x表示叉x上的苹果变化了:有过原来有则现在没有,原来没有则现在有了
Q x表示叉x上方子树中的苹果数量,包括x叉上的苹果(如果存在的话)
3
1 2
1 3
3
Q 1
C 2
Q 1

        
思路:

                

我们先把树倒过来,既然要统计每个节点的变动,每变动一次就统计一次不现实。

那就把树所有节点按照dfs顺序映射成一维数组a,再利用时间戳就把求节点孩子问题变成了求时间戳的区间和问题

                
既要统计a的区间和又要考虑到节点的变动,那就创建树状数组c来维护a。节点的变动恰好对应了点更新。

红色代表L,蓝色代表R, 可见每个点的时间戳,不难看出每个节点的R-L就是这个节点的孩子数量

#include <bits/stdc++.h>
#define lowbit(x) (x)&(-x)//求区间长度
using namespace std;
const int maxn=1e5+10;
int n,q;
int c[maxn],a[maxn];
int L[maxn],R[maxn];
int head[maxn];
int cnt,dfn;
struct edge{int u,v,next;}e[2*maxn];

void adde(int u,int v){e[++cnt]={u,v,head[u]};head[u]=cnt;}

int sum(int i){//求前缀和,
	int ans=0;
	for(;i>0;i-=lowbit(i)) ans+=c[i];
	return ans;
}

void add(int i,int val){//在第i点上加val,修改找后继
	for(;i<=n;i+=lowbit(i)) c[i]+=val;
}

void init(){
	memset(c,0,sizeof(c));
	memset(L,0,sizeof(L));
	memset(R,0,sizeof(R));
	memset(head,0,sizeof(head));
	cnt=0;dfn=0;//因为深度优先的序列是从1开始的
	for(int i=1;i<=n;i++)a[i]=1,add(i,1);//a[i]是1表示该分支i上有苹果
}

void dfs(int u,int fa){//之所以写fa,是防止走父子边,这样子的话vis就不再需要了
	L[u]=++dfn;//相当于是时间戳,根节点是1
	for(int i=head[u];i;i=e[i].next){
		int v=e[i].v;
		if(v==fa)continue;
		dfs(v,u);
	}
	R[u]=dfn;//记录时间戳
}

int main(){
	cin>>n;
	int u,v;
	init();
	for(int i=1;i<n;i++){
		scanf("%d%d",&u,&v);
		adde(u,v);
	}	
	dfs(1,1);
	cin>>q;
	char op[10];//之所以定义字符串,就是因为字符型于回车不兼容,所以换成字符串输入不怕回车
	for(int i=1;i<=q;i++){
		getchar();
		scanf("%s %d",op,&v);//不用考虑回车问题
		if(op[0]=='C'){
			if(a[L[v]]) add(L[v],-1);
			else add(L[v],1);
			a[L[v]]^=1;//0变1,1变0
		}
		else{
			int s1=sum(R[v]);
			int s2=sum(L[v]-1);
			printf("%d\n",s1-s2);
		}
	}
}

        

        

POJ2352:星星

在平面上有n个星星,每颗星星都有自己的坐标。规定星星的等级数为纵横坐标均不超过自己的星星数量(不包括自己),请输出每个级别的星星数量
输入保证y是递增的,且如果y相等,那么x是递增的。
5
1 1
5 1
7 1
3 3
5 5

        
思路:

看似是二维前缀和,实际上y是排好顺序的,那也就是说只需要按y的顺序计算每个x的前缀和即可。相当于加入一个x就统计一下x的前缀和。
        

#include<bits/stdc++.h>
using namespace std;
#define maxn 32005
#define lowbit(x) (x)&(-x)
int ans[maxn],c[maxn];
int n;

void add(int i,int val){
	while(i<=maxn){
	c[i]+=val;
	i+=lowbit(i);
	}	
}

int sum(int i){//统计前缀和
	int s=0;
	while(i>0){
		s+=c[i];
		i-=lowbit(i);
	}
	return s;
}
int main(){
	cin>>n;
	int x,y;
	for(int i=0;i<n;i++){
		scanf("%d%d",&x,&y);
		x++;//注意给的坐标x是从0开始的,树状数组的下标必须从0开始,所以都加1
		ans[sum(x)]++;
		add(x,1);//x的数量加1
	}
	for(int i=0;i<n;i++){//一共最多n-1个等级
		printf("%d\n",ans[i]);
	}
}


http://www.niftyadmin.cn/n/5251194.html

相关文章

LNMP网站架构分布式搭建部署

1. 数据库的编译安装 1. 安装软件包 2. 安装所需要环境依赖包 3. 解压缩到软件解压缩目录&#xff0c;使用cmake进行编译安装以及模块选项配置&#xff08;预计等待20分钟左右&#xff09;&#xff0c;再编译及安装 4. 创建mysql用户 5. 修改mysql配置文件&#xff0c;删除…

CentOS 7 离线安装MySQL审计插件

命令行 cd /data/toolssz mariadb-10.2.38-linux-x86_64.tar.gztar -zxvf mariadb-10.2.38-linux-x86_64.tar.gzinstall lib/plugin/server_audit.so /usr/lib64/mysql/plugin/mysql -uroot -prootinstall plugin server_audit SONAME server_audit.so;show variables like &q…

NestJS的微服务实现

1.1 基本概念 微服务基本概念&#xff1a;微服务就是将一个项目拆分成多个服务。举个简单的例子&#xff1a;将网站的登录功能可以拆分出来做成一个服务。 微服务分为提供者和消费者&#xff0c;如上“登录服务”就是一个服务提供者&#xff0c;“网站服务器”就是一个服务消…

洛谷P1287 盒子与球

题干&#xff1a; 现有 r 个互不相同的盒子和 n 个互不相同的球&#xff0c;要将这 n 个球放入 r 个盒子中&#xff0c;且不允许有空盒子。请求出有多少种不同的放法。 两种放法不同当且仅当存在一个球使得该球在两种放法中放入了不同的盒子。 数据范围&#xff1a; 0<n,r&l…

Python ZeroMQ编程 网络通信协议详细说明和教程

ZeroMQ概述 ZeroMQ&#xff08;又名MQ&#xff0c;MQ&#xff0c;或zmq&#xff09;像一个可嵌入的网络库&#xff0c;但其作用就像一个并发框架。 ZeroMQ类似于标准Berkeley套接字&#xff0c;其提供了各种传输工具&#xff0c;如进程内、进程间、TCP和组播中进行原子消息传送…

从网页抓取数据到Pandas运算,再到MySQL的大数据处理---提效率篇

前言: 在处理网络数据时&#xff0c;从网页抓取表格数据并分析它们是一项常见任务。这篇文章介绍一种有效的工作流程&#xff0c;包含数据抓取、使用Pandas进行逻辑运算&#xff0c;以及对于大量数据运用MySQL的策略。 抓取并保存数据 当从网页上抓取数据时&#xff0c;直接进…

C Primer Plus (中文版)第9章编程练习 参考答案

C Primer Plus &#xff08;中文版&#xff09;第9章编程练习 参考答案 &#x1f334; C Primer Plus第9章编程练习~ 加油加油&#xff01;&#x1f36d; ☘️欢迎大家讨论 批评指正~ 文章目录 C Primer Plus &#xff08;中文版&#xff09;第9章编程练习 参考答案第1题第2题第…

c++新经典模板与泛型编程:const修饰符的移除与增加

const修饰符的移除 让你来写移除const修饰符&#xff0c;你会怎么样来写&#xff1f; &#x1f602;&#x1f602;trait类模板&#xff0c;如下 #include <iostream>// 泛化版本 template<typename T> struct RemoveConst {using type T; };// 特化版本 template…