线段树树套树杭电ojLuck and Love

Posted 行码棋

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线段树树套树杭电ojLuck and Love相关的知识,希望对你有一定的参考价值。

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

题目链接

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

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

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

#include<bits/stdc++.h>
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef vector<int> vi;
typedef vector<ll> 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("-1\\n");
				else printf("%.1lf\\n",ans/10.0);
			}
		}
	}
}
int main()
{
//	ios::sync_with_stdio(false);
//	cin.tie(0),cout.tie(0);
	int _;
//	cin>>_;
	_ = 1;
	while(_--)
	{
		solve();
	}
	return 0;
}

往期优质文章推荐

以上是关于线段树树套树杭电ojLuck and Love的主要内容,如果未能解决你的问题,请参考以下文章

浅谈二维线段树的几种不同的写法

BZOJ3196二逼平衡树树套树

线段树杭电ojTunnel Warfare

「luogu3380」模板二逼平衡树(树套树)

树套树-线段树套平衡树

模板二逼平衡树(树套树)