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