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

来源:互联网 发布:巨人网络公司地址 编辑:程序博客网 时间:2024/05/02 01:03

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了。



原创粉丝点击