#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = 50010;
struct Range
{
int a;
int b;
int c;
inline bool operator < (const Range& other) const
{
return b < other.b;
}
};
Range range[MAXN];
bool used[MAXN];
struct BinaryIndexedTree
{
int bit[MAXN];
int size;
BinaryIndexedTree(){}
inline void init(int size)
{
this->size = size;
memset(bit, 0, sizeof(bit));
}
inline int sum(int i)
{
++i;
int s = 0;
while (i > 0)
{
s += bit[i];
i -= (i & -i);
}
return s;
}
inline int sum(int from, int to)
{
return sum(to - 1) - sum(from - 1);
}
inline void add(int i, int v)
{
++i;
while (i <= size)
{
bit[i] += v;
i += (i & -i);
}
}
};
BinaryIndexedTree bit;
int main(int argc, char *argv[])
{
int n;
scanf("%d", &n);
bit.init(MAXN);
for (int i = 0; i < n; ++i) scanf("%d%d%d", &range[i].a, &range[i].b, &range[i].c);
sort(range, range + n);
int result = 0;
for (int i = 0; i < n; i++)
{
int picked = bit.sum(range[i].a, range[i].b + 1);
if (picked < range[i].c)
{
int remain = range[i].c - picked;
result += remain;
int tail = range[i].b;
while (remain)
{
if (used[tail] == false)
{
used[tail] = true;
bit.add(tail, 1);
--remain;
}
--tail;
}
}
}
printf("%d\n", result);
return 0;
}
题意:给出
n个闭区间
[ai,bi],每个区间对应一个
ci,表示集合
Z在区间
[ai,bi]内
ci个相同元素,问集合
Z至少有几个元素。
思路:将区间[ai,bi]的每个端点看做一个顶点,以dist[i+1]表示源点x到i之间至少有与集合Z相同元素的个数。如果将至少含有的相同元素的个数看做边的权值则一个区间[ai,bi]的两个端点的dist[ai]和dist[bi+1]分别表示源点x到ai-1和bi的距离。那么区间[ai,bi+1]可以看做ai到bi的一条边。依据题意 x、ai、bi构成了一个边权三角形dist[bi+1]-dist[ai]>=ai->bi,即dist[bi+1]-dist[ai]>=ci;所以变形一下就得:dist[bi+1]>=dist[ai]+ci;注意:这个结果只是题目的要求,所以我们if(dist[bi+1]<dist[ai]+ci) dist[bi+1]=dist[ai]+ci;这也决定了求的是最长路径(当然有的人求的是最短路也行)。
挖掘隐藏的条件:0<=dist[i+1]-dist[i]<=1。有了这个条件便可以建立数据结构了,然后我们以出现的最小元素min1为源点spfa,dist[max1]就是解了。