#include <fstream>
#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
#define MAXN 100002
using namespace std;
struct Pole
{
Pole(int xx, int l, int r, int c) :
x(xx),
Left(l),
Right(r),
Cost(c)
{}
int x = 0;
int Left = 0;
int Right = 0;
int Cost = 0;
};
ostream& operator << (ostream& os, Pole pole)
{
os << pole.x << " " << pole.Left << " " << pole.Right << " " << pole.Cost;
return os;
}
bool operator < (const Pole& lhs, const Pole& rhs)
{
return lhs.x < rhs.x;
}
pair<int, int> vRightSortedPoles[MAXN];
long long costs[MAXN];
#define MAX_SIZE 100001
#define GET_0_BASED_INDEX_PARENT(index) (((index)-1-!((index)%2)) / 2)
#define LEFT_SUBTREE(index) (((index)<<1)+1)
#define RIGHT_SUBTREE(index) (((index)+1)<<1)
using namespace std;
typedef unsigned int uint32;
template<class T, class Compare = less<T> >
class IntervalTree
{
public:
IntervalTree(const int size, const T& defaultValue) :
intervalSize(size)
{
vValues = (T*)malloc((size+1)*sizeof(T));
vValues[size] = defaultValue;
intervalTree = (int*)calloc((4*size+2), sizeof(int));
}
inline void Update(const int index, const T& value)
{
vValues[index] = value;
UpdateIndex(index);
}
inline void Update(const int index)
{
UpdateIndex(index);
}
inline void UpdateIndex(const int index)
{
int left = 0, right = intervalSize-1;
int intervalTreeIndex = 0;
while (left < right)
{
const int mid = left + (right-left)/2;
if (index <= mid)
{
intervalTreeIndex = LEFT_SUBTREE(intervalTreeIndex);
right = mid;
}
else
{
intervalTreeIndex = RIGHT_SUBTREE(intervalTreeIndex);
left = mid+1;
}
}
if (left == index)
{
intervalTree[intervalTreeIndex] = index;
int parent = GET_0_BASED_INDEX_PARENT(intervalTreeIndex);
while(parent >= 0)
{
if (compare(vValues[intervalTree[LEFT_SUBTREE(parent)]], vValues[intervalTree[RIGHT_SUBTREE(parent)]]))
{
intervalTree[parent] = intervalTree[LEFT_SUBTREE(parent)];
}
else
{
intervalTree[parent] = intervalTree[RIGHT_SUBTREE(parent)];
}
intervalTreeIndex = parent;
parent = GET_0_BASED_INDEX_PARENT(intervalTreeIndex);
}
}
}
inline int QueryIndex(const int l, const int r) const
{
int intervalTreeIndex = 0;
int left = 0, right = intervalSize-1;
if (l == r)
{
return QueryElementaryInterval(l);
}
int mid = left + (right-left)/2;
while (r <= mid || l > mid)
{
if (r <= mid)
{
right = mid;
intervalTreeIndex = LEFT_SUBTREE(intervalTreeIndex);
}
else if (l > mid)
{
left = mid+1;
intervalTreeIndex = RIGHT_SUBTREE(intervalTreeIndex);
}
mid = left + (right-left)/2;
}
const int leftIndex = QueryLeftSubInterval(left, mid, l, LEFT_SUBTREE(intervalTreeIndex));
const int rightIndex = QueryRightSubInterval(mid+1, right, r, RIGHT_SUBTREE(intervalTreeIndex));
if (compare(vValues[leftIndex], vValues[rightIndex]))
{
return leftIndex;
}
return rightIndex;
}
inline T& QueryValue(const int l, const int r)
{
return vValues[QueryIndex(l,r)];
}
inline const T& QueryValue(const int l, const int r) const
{
return vValues[QueryIndex(l,r)];
}
inline T& GetValueAt(const int index)
{
return vValues[index];
}
inline const T& GetValueAt(const int index) const
{
return vValues[index];
}
private:
inline int QueryElementaryInterval(const int index) const
{
int left = 0, right = intervalSize-1;
int intervalTreeIndex = 0;
while (left < right)
{
const int mid = left + (right-left)/2;
if (index <= mid)
{
intervalTreeIndex = LEFT_SUBTREE(intervalTreeIndex);
right = mid;
}
else
{
intervalTreeIndex = RIGHT_SUBTREE(intervalTreeIndex);
left = mid+1;
}
}
if (left == index)
{
return intervalTree[intervalTreeIndex];
}
return intervalTree[intervalSize];
}
inline int QueryLeftSubInterval(int left, int right, const int finalLeft, int intervalTreeIndex) const
{
int foundIndex = intervalSize;
while (finalLeft != left)
{
const int mid = left + (right-left)/2;
if (finalLeft <= mid)
{
if (compare(vValues[intervalTree[RIGHT_SUBTREE(intervalTreeIndex)]], vValues[foundIndex]))
{
foundIndex = intervalTree[RIGHT_SUBTREE(intervalTreeIndex)];
}
intervalTreeIndex = LEFT_SUBTREE(intervalTreeIndex);
right = mid;
}
else
{
left = mid+1;
intervalTreeIndex = RIGHT_SUBTREE(intervalTreeIndex);
}
}
if (compare(vValues[intervalTree[intervalTreeIndex]], vValues[foundIndex]))
{
foundIndex = intervalTree[intervalTreeIndex];
}
return foundIndex;
}
inline int QueryRightSubInterval(int left, int right, const int finalRight, int intervalTreeIndex) const
{
int foundIndex = intervalSize;
while (finalRight != right)
{
const int mid = left + (right-left)/2;
if (finalRight > mid)
{
if (compare(vValues[intervalTree[LEFT_SUBTREE(intervalTreeIndex)]], vValues[foundIndex]))
{
foundIndex = intervalTree[LEFT_SUBTREE(intervalTreeIndex)];
}
intervalTreeIndex = RIGHT_SUBTREE(intervalTreeIndex);
left = mid+1;
}
else
{
right = mid;
intervalTreeIndex = LEFT_SUBTREE(intervalTreeIndex);
}
}
if (compare(vValues[intervalTree[intervalTreeIndex]], vValues[foundIndex]))
{
foundIndex = intervalTree[intervalTreeIndex];
}
return foundIndex;
}
Compare compare;
const int intervalSize;
int *intervalTree;
T *vValues;
};
int main()
{
int n;
vector<Pole> vPoles;
fstream fin("stalpi.in", fstream::in);
fstream fout("stalpi.out", fstream::out);
fin >> n;
//cout << n << endl;
vPoles.reserve(n+2);
vPoles.push_back(Pole(- (1 << 30), 0, 0, 0));
for (int i=0; i<n; ++i)
{
int x, l, r, c;
fin >> x >> c >> l >> r;
vPoles.push_back(Pole(x, l, r, c));
}
sort(begin(vPoles), end(vPoles));
for (int i=0; i<n; ++i)
{
vRightSortedPoles[i] = make_pair(vPoles[i+1].x + vPoles[i+1].Right, i+1);
}
sort(begin(vRightSortedPoles), begin(vRightSortedPoles) + n);
int maxPoleX = vRightSortedPoles[n-1].first + 1;
vPoles.push_back(Pole(maxPoleX + 1, 0, 0, 0));
ostream_iterator<int> itOut(cout, " ");
ostream_iterator<Pole> itOutPoles(cout, "\n");
/*copy_n(begin(vPoles), n + 2, itOutPoles);
cout << endl;
for (int i=0; i<n; ++i)
{
cout << vRightSortedPoles[i].first << " " << vRightSortedPoles[i].second << endl;
}
cout << endl;*/
for (int i=1; i<=n; ++i)
{
costs[i] = 1LL << 61;
}
IntervalTree<long long, less<long long> > intervalTree(n+2, 1LL << 61);
intervalTree.Update(0, 0);
for (int i=1; i<=n; ++i)
{
intervalTree.Update(i, 1LL << 61);
}
for (int i=0; i<n; ++i)
{
long long minVal = 1LL << 61;
Pole pole(vPoles[vRightSortedPoles[i].second].x - vPoles[vRightSortedPoles[i].second].Left, 0, 0, 0);
int L = lower_bound(begin(vPoles), end(vPoles), pole) - begin(vPoles) - 1;
pole = Pole(vRightSortedPoles[i].first + 1, 0, 0, 0);
int R=lower_bound(begin(vPoles), end(vPoles), pole) - begin(vPoles) - 1;
minVal = intervalTree.QueryValue(L, n) + vPoles[vRightSortedPoles[i].second].Cost;
/*for (int k=L; k<=R; ++k)
{
minVal = min(minVal, costs[k] + vPoles[vRightSortedPoles[i].second].Cost);
}*/
//cout << L << " " << R << endl;
costs[R] = min(costs[R], minVal);
intervalTree.Update(R, costs[R]);
/*for (int k=1; k<=R; ++k)
{
costs[k] = min(costs[k], minVal);
}*/
}
/*for (int i=0; i<=n; ++i)
{
cout << costs[i] << " ";
}
cout << endl;*/
fout << costs[n] << "\n";
return 0;
}