HDU4132 How Far Can Drive At Most 离散化+树状数组/线段树

12 篇文章 0 订阅
9 篇文章 0 订阅

Problem Address:http://acm.hdu.edu.cn/showproblem.php?pid=4132


【前言】


没想到这么简单的一道题可以被做的这么复杂= =

拿到题想到可以用离散化,于是很快就想出来了。

(其实想到离散化的时候还想到了线段树,但是后面居然把这么重要的东西忘了。)

开始时偷懒,用hash和set写了交上去,返回TLE。

觉得可能是stl太慢了,于是去掉hash和set,写了个二分,又TLE了。

自己的二分一直都不敢保证,于是换了个bsearch,还是TLE。

突然发现,原来修改段的时候应该不能线性扫描!

于是添加了个树状数组进去,便华丽丽的AC了。

然后把自己的二分也改好了。


【思路】


将所有可能的点离散化,最多有100000个点。

扫描所有段,对于要增加时间的段都要修改。包括一开始对所有段都加1。

要注意的是,比如段[a,b],则修改[a,b-1]。

这样做的好处是扫描时只需对当前结点判断即可。

然后从小到大扫描所有结点,查出当前段的值。

如果这段路可以走完,则继续走。否则结束。同时计算路程。


想必这道题数据比较水,没用__int64还AC了。

其实一开始用树状数组的时候还提醒自己要用__int64的,结果……


【代码】


//树状数组版本【修改区间,查询节点】(具体参考这里

#include <iostream>
#include <string>
#include <cmath>
#include <vector>
#include <set>
#include <map>
#include <algorithm>
using namespace std;

const int maxn = 50000;

struct node
{
	int s;
	int e;
	int v;
}seg[maxn+5];

struct hashnode
{
	int rv;
	int id;
}index[maxn*2+5];

bool cmp(const hashnode &a, const hashnode &b)
{
	return a.rv<b.rv;
}

int f[maxn*2+5];

inline int lowbit(int x)
{
	return x & (-x);
}

inline void _update(int x, int d)
{
	int i;
	for (i=x; i>0; i-=lowbit(i))
	{
		f[i] += d;
	}
}

inline void update(int l, int r, int d)
{
	_update(l-1, -d);
	_update(r, d);
}

inline int getpt(int x, int n)
{
	int i, s = 0;
	for (i=x; i<=n; i+=lowbit(i))
	{
		s += f[i];
	}
	return s;
}

int bs(int v, int s, int t)
{
	int l=s-1, r=t+1, m, ans;
	while(l<=r)
	{
		m = (l+r)>>1;
		if (v<=index[m].rv)
		{
			ans = m;
			r = m-1;
		}
		else l = m+1;
	}
	return index[ans].id;
}

int main()
{
	int t;
	int len;
	double amt;
	int n;
	int i, j;
	int a, b;
	int end;
	double ans;
	scanf("%d", &t);
	while(t--)
	{
		scanf("%d %lf", &len, &amt);
		scanf("%d", &n);
		index[1].rv = 0;
		index[2].rv = len;
		for (i=0,j=3; i<n; i++,j+=2)
		{
			scanf("%d %d %d", &seg[i].s, &seg[i].e, &seg[i].v);
			index[j].rv = seg[i].s;
			index[j+1].rv = seg[i].e;
		}
		end = j-1;
		sort(index+1, index+end+1, cmp);
		index[1].id = 1;
		for (i=2,j=2; i<=end; i++)
		{
			if (index[i].rv!=index[j-1].rv)
			{
				index[j].rv = index[i].rv;
				index[j].id = j;
				j++;
			}
		}
		end = j-1;
		memset(f, 0, sizeof(f));
		update(1, end-1, 1);
		for (i=0; i<n; i++)
		{
			a = bs(seg[i].s, 1, end);
			b = bs(seg[i].e, 1, end);
			update(a, b-1, seg[i].v);
		}
		ans = 0;
		for (i=1; i<end && fabs(amt)>1e-6; i++)
		{
			a = index[i+1].rv-index[i].rv;
			b = getpt(i, end);
			if (a*1.0>amt/b)
			{
				ans += amt/b;
				amt = 0;
			}
			else
			{
				ans += a;
				amt -= a*b;
			}
		}
		printf("%.2lf\n", ans);
	}
	return 0;
}


//线段树版本

#include <iostream>
#include <string>
#include <cmath>
#include <vector>
#include <set>
#include <map>
#include <algorithm>
using namespace std;

const int maxn = 50000;

struct node
{
	int s;
	int e;
	int v;
}seg[maxn+5];

struct hashnode
{
	int rv;
	int id;
}index[maxn*2+5];

bool cmp(const hashnode &a, const hashnode &b)
{
	return a.rv<b.rv;
}

int bs(int v, int s, int t)
{
	int l=s-1, r=t+1, m, ans;
	while(l<=r)
	{
		m = (l+r)>>1;
		if (v<=index[m].rv)
		{
			ans = m;
			r = m-1;
		}
		else l = m+1;
	}
	return index[ans].id;
}

struct treenode
{
	int left, right;
	treenode *pl, *pr;
	int add;
}tree[maxn*4+5];

int tct;

treenode *new_node()
{
	treenode *p = &tree[tct++];
	p->pl = p->pr = NULL;
	p->left = p->right = -1;
	p->add = 0;
	return p;
}

treenode *init(int l, int r)
{
	treenode *root;
	root = new_node();
	root->left = l;
	root->right = r;
	root->add = 0;
	if (l!=r)
	{
		int m = (l+r)/2;
		root->pl = init(l, m);
		root->pr = init(m+1, r);
	}
	return root;
}

void updatetree(treenode *root, int l, int r, int d)
{
	int m = (root->left+root->right)>>1;
	if (l==root->left && r==root->right)
	{
		root->add += d;
		return; 
	}
	if (r<=m)
	{
		updatetree(root->pl, l, r, d);
	}
	else if (l>m)
	{
		updatetree(root->pr, l, r, d);
	}
	else 
	{
		updatetree(root->pl, l, m, d);
		updatetree(root->pr, m+1, r, d);
	}
}

int get(treenode *root, int v)
{
	if (root->left==root->right) return root->add;
	int m = (root->left+root->right)>>1;
	if (v<=m) return get(root->pl, v) + root->add;
	else return get(root->pr, v) + root->add;
}

int main()
{
	int t;
	int len;
	double amt;
	int n;
	int i, j;
	int a, b;
	int end;
	double ans;
	scanf("%d", &t);
	while(t--)
	{
		scanf("%d %lf", &len, &amt);
		scanf("%d", &n);
		index[1].rv = 0;
		index[2].rv = len;
		for (i=0,j=3; i<n; i++,j+=2)
		{
			scanf("%d %d %d", &seg[i].s, &seg[i].e, &seg[i].v);
			index[j].rv = seg[i].s;
			index[j+1].rv = seg[i].e;
		}
		end = j-1;
		sort(index+1, index+end+1, cmp);
		index[1].id = 1;
		for (i=2,j=2; i<=end; i++)
		{
			if (index[i].rv!=index[j-1].rv)
			{
				index[j].rv = index[i].rv;
				index[j].id = j;
				j++;
			}
		}
		end = j-1;

		tct = 0;
		treenode *root;
		root = init(1, end);
		updatetree(root, 1, end-1, 1);

		for (i=0; i<n; i++)
		{
			a = bs(seg[i].s, 1, end);
			b = bs(seg[i].e, 1, end);
			updatetree(root, a, b-1, seg[i].v);
		}
		ans = 0;
		for (i=1; i<end && fabs(amt)>1e-6; i++)
		{
			a = index[i+1].rv-index[i].rv;
			b = get(root, i);
			if (a*1.0>amt/b)
			{
				ans += amt/b;
				amt = 0;
			}
			else
			{
				ans += a;
				amt -= a*b;
			}
		}
		printf("%.2lf\n", ans);
	}
	return 0;
}


【P.S】


jay说线段树不好搞,我说不会,跟树状数组一样。

他说要分很多种情况,我说肯定是你理解错了。

于是打出了线段树的版本。

虽然平时基本都是偷懒,只打树状数组不打线段树。

但是这里1A了。



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值