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