bzoj3110常数巨大的线段树套线段树......

这种题目一般是一个权值线段树套一个区间线段树可以改成树状数组套线段树。。。不解释了很常规......树套树恶心
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
unsigned int sum[15000010], tree[300000], lson[15000010], rson[15000010],t[15000010];
unsigned int n, m;
unsigned int cnt = 1;
void intervaladd(unsigned int &num, int l, int r,int nowl,int nowr)
{
	if (nowl > r || nowr < l)return;
	if (num == 0)
		num = cnt++;
    int mid = (nowl + nowr) >> 1;
	if (nowl >= l&&nowr <= r)
	{
		sum[num] += (nowr - nowl + 1);
		t[num]++;
		//cout << "num:"<<num<<" "<<"posl:" << l << "posr:" << r << " " << "nowposl:" << nowl << " " << "nowposr:" << nowr << "sum:"<<sum[num]<<endl;
		return;
	}
	if (mid >= l&&nowl <= r)intervaladd(lson[num], l, r, nowl, mid);
	if (mid < r&&nowr>=l)intervaladd(rson[num], l, r, mid + 1, nowr);
	sum[num] = sum[lson[num]] + sum[rson[num]] + t[num] * (nowr - nowl + 1);
	//cout <<"num:"<<num<<" "<<"l:" << l << "r:" << r << " " << "nowl:" << nowl << " " << "nowr:" << nowr << "sum:" << sum[num] << endl;
}
unsigned int intervalquery( int num,  int l,  int r,  int nowl,int nowr)
{
	if (nowl > r || nowr < l)
		return 0;
	 int mid = (nowl + nowr) >> 1;//这个又写错了   论写代码专注思路清晰的重要性......
	if (num == 0)
		return 0;
	if (nowl >= l&&nowr <= r)
	{
		//cout <<"num:"<<num<<" "<< "posl:" << " " <<nowl << " " << "posr:" << nowr<< " " << "sum:"<<sum[num] << endl;
		return sum[num];
	}
	unsigned int kl = 0; unsigned int kr = 0;
	if (mid>=l)
	 kl = intervalquery(lson[num], l, r, nowl, mid);
	if (mid<r)
	 kr = intervalquery(rson[num], l, r, mid + 1, nowr);
	//cout << "posl:" << " " << nowl << " " << "posr:" << nowr << " " << "sum:"<<(min(nowr, r) - max(l, nowl) + 1)*t[num] + kl + kr << endl;
	return (min(nowr, r) - max(l, nowl) + 1)*t[num] + kl + kr;
}
void addvalue( int a,  int b, int c)
{
	 int l = 0; int r = 2*n;
	c += n;
	 int id = 1;
	while (l <=r)
	{
		//cout << endl;
		//cout << "begin:" << "l:"<<l<<" "<<"r:"<<r<<endl;
		intervaladd(tree[id], a, b, 1, n);
		//cout << "end:" << endl;
		//cout << endl;
		unsigned int mid = (l + r) >> 1;
		if (l == r)break;
		c<=mid ? (id = 2 * id, r = mid ): (id = 2 * id + 1, l = mid + 1);//这一定要加括号
	}
}
 int queryvalue(int a, int b, unsigned int c)
{
	int l = 0; int r = n * 2;
	int id = 1;
	while (l < r)
	{
		int mid = (l + r) >> 1;
		//cout << endl;
		//cout << "begin:" << "numl:" << mid + 1 << " " << "numr:" << r << " " << "posl:" << a << " " << "posr:" << b << " " << endl;
		unsigned int k = intervalquery(tree[id * 2 + 1], a, b, 1, n);
		//cout << "result:" << k << endl;
	//	cout << "end:" << endl;
	//	cout << endl;
		if (c > k)
		{
			c -= k;
			r = mid;
			id = id * 2;
		}
		else
		{
			l = mid+1;
			id = 2 * id+1;
		}
	}
	return l-n;
}
int main()
{
	scanf("%d%d", &n, &m);
	int op;
	for (int i = 0; i < m; i++)
	{
		scanf("%d", &op);
		int a, b, c;
		scanf("%d%d%d", &a, &b, &c);
		if (op == 1)
		{
			addvalue(a, b, c);
		}
		else
			printf("%u\n", queryvalue(a, b, c));
	}
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值