hihoCoder 1034 毁灭者问题

这题网上有题解,贴这题主要是记录自己以前写的SBT,觉得maintain 和左右旋写得比较好,可能板子比我写得好.不过没看过.

ch[x][2]代表sbt的两个孩子.

今天突然发现前面写的平衡树有点错误.

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <set>
#pragma warning(disable:4996)
using namespace std;
int n;
const int bign = 100033;
int s[bign];
int m[bign];
int r[bign];

int q;
int nid;

int msize[6*bign];
int num[6*bign];
int ch[6*bign][2];
int tseq[bign];
int ep[bign];
int sp[bign];
int te[bign];
int ts[bign];
int mroot;

long long int sumT;
long long int tsumT[6*bign];
int vst[bign];
set<int> mset1;
set<int> mset2;


bool cmpts(int x1, int y1)
{
	if (sp[x1] < sp[y1] || (sp[x1] == sp[y1] && x1 < y1))
		return true;
	return false;
}

bool cmpte(int x1, int y1)
{
	if (ep[x1] < ep[y1] || (ep[x1] == ep[y1] && x1 < y1))
		return true;
	return false;
}

inline void pushup(int &x)
{
	msize[x] = msize[ch[x][0]] + msize[ch[x][1]] + 1;
	tsumT[x] = tsumT[ch[x][0]] + tsumT[ch[x][1]] + num[x];
}

inline void rotate(int &x, int flag)//flag = 1 rotate with rightchild
{
	int nroot = ch[x][flag];
	ch[x][flag] = ch[nroot][!flag];
	ch[nroot][!flag] = x;
	pushup(x);
	pushup(nroot);
	x = nroot;
}

void maintain(int &x, int flag)
{
	int &m2 = ch[x][flag];
	int &m1 = ch[x][!flag];
	if (msize[ch[m2][!flag]] > msize[m1])
	{
		rotate(m2, !flag);
		rotate(x, flag);
	}
	else if (msize[ch[m2][flag]] > msize[m1])
	{
		rotate(x, flag);
	}
	else
	{
		return;
	}
	maintain(ch[x][0], 0);
	maintain(ch[x][1], 1);
	maintain(x, 1);
	maintain(x, 0);
}

inline int Query(const int &mroot, int x)
{
	int troot = mroot;
	int ret = 0;
	sumT = 0;
	while (troot)
	{
		if (x >= num[troot])
		{
			ret += (1 + msize[ch[troot][0]]);
			sumT += tsumT[ch[troot][0]] + num[troot];
			troot = ch[troot][1];
		}
		else
		{
			troot = ch[troot][0];
		}
	}
	return ret;
}
void minsert(int &nowroot, int x)
{
	if (nowroot == 0)
	{
		nid++;
		msize[nid] = 1;
		num[nid] = x;
		tsumT[nid] = x;
		nowroot = nid;
		return;
	}
	msize[nowroot]++;
	tsumT[nowroot] += x;
	if (num[nowroot] < x)
	{
		minsert(ch[nowroot][1], x);
	}
	else
	{
		minsert(ch[nowroot][0], x);
	}
	//pushup(nowroot);
	maintain(nowroot, (x > num[nowroot]));
}

int mdelete(int &nowroot, int x)
{
	//msize[nowroot]--;
	int ret = 0;
	if (x == num[nowroot] || (x > num[nowroot] && !ch[nowroot][1]) || (x < num[nowroot] && !ch[nowroot][0]))
	{
		if (!ch[nowroot][0])
		{
			ret = num[nowroot];
			nowroot = ch[nowroot][1];
			return ret;
		}
		else if (!ch[nowroot][1])
		{
			ret = num[nowroot];
			nowroot = ch[nowroot][0];
			return ret;
		}
		else
		{
			 num[nowroot] = mdelete(ch[nowroot][0], x + 1);
			 pushup(nowroot);
			 return num[nowroot];
		}
	}
	else
	{
		if (x > num[nowroot])
		{
			int tmp = mdelete(ch[nowroot][1], x);
			pushup(nowroot);
			return tmp;
		}
		else
		{
			int tmp = mdelete(ch[nowroot][0], x);
			pushup(nowroot);
			return tmp;
		}	
	}
	
}
int main()
{
	scanf("%d", &n);
	for (int i = 1; i <= n; i++)
	{
		scanf("%d%d%d", s + i, m + i, r + i);
	}
	scanf("%d", &q);
	for (int i = 1; i <= q; i++)
	{
		//int t, ts, te;
		ts[i] = i;
		te[i] = i;
		scanf("%d%d%d", &tseq[i], &sp[i], &ep[i]);
	}
	sort(ts + 1, ts + q + 1, cmpts);
	sort(te + 1, te + q + 1, cmpte);
	int nowl = 1;
	int nowr = 1;
	mroot = 0;
	long long int ans = 0;
	memset(vst, -1, sizeof(vst));
	for (int i = 1;i <= n; i++)
	{	
		while (sp[ts[nowl]] <= i && nowl <= q)
		{
			int t1 = ts[nowl];
			set<int>::iterator lb1 = mset1.upper_bound(t1);
			int tcnt = 0;
			int tsum = 0;
			if (lb1 != mset1.end())
			{
				tcnt++;
				tsum += tseq[*lb1] - tseq[t1];
				minsert(mroot, tseq[*lb1] - tseq[t1]);
			}

			lb1 = mset2.upper_bound(-t1);
			if (lb1 != mset2.end())
			{
				tcnt++;
				tsum += tseq[t1] - tseq[-*lb1];
				minsert(mroot, tseq[t1] - tseq[-*lb1]);
			}

			if (tcnt == 2)
			{
				mdelete(mroot, tsum);
			}
			mset1.insert(t1);
			mset2.insert(-t1);
			nowl++;
		}
		if (mset1.size() > 0)
			vst[i] = *mset1.begin();
		if (msize[mroot] > 0)
		{
			if (r[i] > 0)
			{
				int x = Query(mroot, m[i] / r[i]);
				ans += 1ll * sumT * r[i] + 1ll * m[i] * (msize[mroot] - x);
			}
		}
		while (ep[te[nowr]] <= i && nowr <= q)
		{
			int t2 = te[nowr];
			int tcnt = 0;
			int tsum = 0;
			set<int>::iterator lb1 = mset1.upper_bound(t2);
			if (lb1 != mset1.end())
			{
				tcnt++;
				tsum += tseq[*lb1] - tseq[t2];
				mdelete(mroot, tseq[*lb1] - tseq[t2]);
			}

			lb1 = mset2.upper_bound(-t2);
			if (lb1 != mset2.end())
			{
				tcnt++;
				tsum += tseq[t2] - tseq[-*lb1];
				mdelete(mroot, tseq[t2] - tseq[-*lb1]);
			}

			if (tcnt == 2)
				minsert(mroot, tsum);
			mset1.erase(t2);
			mset2.erase(-t2);
			
			nowr++;
		}
	//	printf("%lld\n", ans);
	}


	for (int i = 1; i <= n; i++)
	{
		if (vst[i] >= 0)
		{
			ans += (s[i] + 1ll * tseq[vst[i]] * r[i] < m[i]) ? (s[i] + 1ll * tseq[vst[i]] * r[i]) : m[i];
		}
	}
	printf("%lld\n", ans);

}

/*
12
0 10 1
0 12 1
0 20 1
0 12 1
0 10 1
0 10 1
0 10 1
0 10 1
0 10 1
0 10 1
0 10 1
0 10 1
2 100 10
7
5 1 5
6 1 5
7 1 5
20 1 5
40 5 10
100 2 3
1000 1 12
*/

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值