栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

【线段树】【树套树】【杭电oj】Luck and Love

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

【线段树】【树套树】【杭电oj】Luck and Love

  • 博客主页: https://blog.csdn.net/qq_50285142
  • 欢迎点赞收藏✨关注❤留言  如有错误,敬请指正
  • 虽然生活很难,但我们也要一直走下去
题目链接

思路:
问题是要询问满足两个区间的最大缘分值,因为一个树只能记录一个区间,我们只能再弄个树,所以就是树套树了。同时还要记录最大值。

主树记录身高这个区间,附树记录活泼度这个区间,同时记录最大值。
每个线段树节点都要声明一颗线段树,来记录满足身高区间内的其它情况。
所以都要有两个函数,一个是主树的,一个是附树的。

建树思路和单个基本一样,就是在访问每个主线段树节点时,都要对每个节点上的子线段树进行操作。
同时注意初始化-1,而且变量记录的可能比较多

#include
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef pair pii;
typedef pair pll;
typedef vector vi;
typedef vector vl;
const int dx[]={-1,0,1,0},dy[]={0,1,0,-1};
const int inf = 0x3f3f3f3f;
const ll linf = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-6;
const int mod = 1e9+7;
const int N = 100,M = 1000;

int n,m,k;

struct son
{
	int l,r;
	int mx;
};//附树
struct parent
{
	int l,r;
	son so[M*4];
}tr[N*4];//主树

//主线段树的节点,子线段树访问到的节点,子线段树左区间,右区间
void sbuild(int root,int u,int l,int r)
{
	tr[root].so[u] = {l,r,-1};
	if(l==r) return ;
	int mid = l + r >> 1;
	sbuild(root,u<<1,l,mid);
	sbuild(root,u<<1|1,mid+1,r);	
}

//主线段树的节点,身高区间,活泼度区间
void build(int u,int l1,int r1,int l2,int r2)
{
	tr[u] = {l1,r1};
	sbuild(u,1,l2,r2);
	if(l1==r1) return ;
	int mid = l1 + r1 >> 1;
	build(u<<1,l1,mid,l2,r2);
	build(u<<1|1,mid+1,r1,l2,r2); 
}

//主线段树的节点,子线段树访问到的节点,活泼度,缘分值
void smodify(int root,int u,int a,int v)
{
	if(tr[root].so[u].l == a && tr[root].so[u].r==a) 
	{
		//可能有多个相同活泼度的值,但缘分值不同,所以要取max
		tr[root].so[u].mx = max(tr[root].so[u].mx,v);
		return;
	}
	int mid = tr[root].so[u].l + tr[root].so[u].r >> 1;
	if(a <= mid) smodify(root,u<<1,a,v);
	else smodify(root,u<<1|1,a,v);
	//修改完要进行pushup操作
	tr[root].so[u].mx = max(tr[root].so[u<<1].mx,tr[root].so[u<<1|1].mx);
}
//主线段树的节点,身高,活泼度,缘分值
void modify(int u,int h,int a,int v)
{
	//主树只记录一个身高区间,只需查区间即可
	smodify(u,1,a,v);
	if(tr[u].l == h && tr[u].r == h) return;
	int mid = tr[u].l + tr[u].r >> 1;
	if(h <= mid) modify(u<<1,h,a,v);
	else modify(u<<1|1,h,a,v);
}
//主线段树的位于的节点,子线段树访问到的节点,活泼度区间
int squery(int root,int u,int l,int r)
{
	if(tr[root].so[u].l>=l && tr[root].so[u].r <=r)
		return tr[root].so[u].mx;
	int mid = tr[root].so[u].l + tr[root].so[u].r >> 1;
	int res = -1;
	if(l <= mid) res = max(res,squery(root,u<<1,l,r));
	if(r > mid) res = max(res,squery(root,u<<1|1,l,r));
	return res;
}
//主线段树的节点,身高区间,活泼度区间
int query(int u,int l1,int r1,int l2,int r2)
{
	if(tr[u].l >= l1 && tr[u].r <= r1)
		return squery(u,1,l2,r2);
	int mid = tr[u].l + tr[u].r >> 1;
	int res = -1;
	if(l1 <= mid) res = max(res,query(u<<1,l1,r1,l2,r2));
	if(r1 > mid) res = max(res,query(u<<1|1,l1,r1,l2,r2));
	return res;
}
void solve()
{
	int h,h1,h2;
	double a,l,a1,a2;
	while(scanf("%d",&n) and n)
	{
		build(1,100,200,0,1000);
		while(n--)
		{
			char s[2];
			scanf("%s",s);
			if(*s=='I')
			{
				scanf("%d %lf %lf",&h,&a,&l);
				modify(1,h,(int)(a*10),(int)(l*10));
			}			
			else
			{
				scanf("%d %d %lf %lf",&h1,&h2,&a1,&a2);
				if(h1>h2) swap(h1,h2);
				if(a1>a2) swap(a1,a2);
				int ans = query(1,h1,h2,(int)(a1*10),(int)(a2*10));
				if(ans<0) printf("-1n");
				else printf("%.1lfn",ans/10.0);
			}
		}
	}
}
int main()
{
//	ios::sync_with_stdio(false);
//	cin.tie(0),cout.tie(0);
	int _;
//	cin>>_;
	_ = 1;
	while(_--)
	{
		solve();
	}
	return 0;
}
往期优质文章推荐
  • C++ STL详解,超全总结(快速入门STL)
  • 李【期末复习】c++知识点大回顾,八篇文章让你永不破防(一)
  • 区间贡献问题习题详解
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/296569.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号