/*

两年前,老师拿这套题来考试,完全只会n^2的做法.

 

但我总是感觉有NlgN的解法.于是各种查题解。发现几乎大家都是最坏情况n^2的算法水过的。

 

一年前想起这道题时。功夫不负有心人,在某一个blog里看到了ld大神NlogN的题解。于是准备等哪天有心情时过掉它。然后就拖到了今天。。。

 

将近两年后再来看,有ld大神题解的那个blog没了....于是大家都是N^2水过的。。。

 

写下这个NlogN的题解(即使代码的长度被完虐),希望哪一天google出来的前几个有NlogN(或者更好0.0)的算法。

*/

我们可以把一个等腰直角三角形想象成一条条不断变短的线段.

性质1:如果一条线段被另一条完全包含了,则这条线段的存在就没有意义了,删掉.

从x轴从左往右做(也可以把x轴想象成时间轴).

用平衡数(我用splay,因为插入时有可能要删除一个区间)维护一个当前时间的线段集合,由于性质1,线段的上端和下端都单调递减

维护出两个数据,总长度L,这些线段的并一共有多少处不连续(记为S)

用堆维护一个x轴坐标为关键字的优先队列.

三种操作

1插入一条线段

2删除一条线段(长度已经减到0了)

3.某条线段不再与上一条线段相交了

ans=Σ(l+l-s*(x2-x1)*(x2-x1)/2//所有时间间隔之间的梯形面积之和

(求点赞,求存在感。。。)

效率分析:

 

每次操作是均摊logN的,只有操作1会最多增加3个操作(删除一个,与前一个线段分离可能有一个,后一个线段与这个线段分离可能有一个)

而一共只有n个操作1

于是效率是NlogN的

代码写得比较捉急...用来对拍还行...要看的话请加油...

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <queue>
 
#define itserror (cout<<"error!!!!!!!!!"<<endl);
using namespace std;
typedef long long LL;
const int mN = 10000 + 10;
const int oo = 100000000;
bool exist[mN] =
{ 0 };
 
struct handle
{
    int time;
    int attr; //1->earse;2->split;3->insert;4->count;
    int argument1, argument2;
    handle()
    {
    }
    ;
    handle(int t, int a, int a1, int a2) :
            time(t), attr(a), argument1(a1), argument2(a2)
    {
    }
    ;
} buf;
priority_queue<handle> heap;
struct splay_tree
{
    struct tree_node
    {
        tree_node()
        {
            tree[0] = 0;
            tree[1] = 0;
            tree[2] = 0;
        }
        ;
        bool is_head; //is_head
        int tot_head;
//      int tot_point;//tot_point
        int tree[3]; //0->left_son;1->right_son;2->father
        int top_plus_time, bottom;
        int add_for_ans;
        int awaytime;
        LL tot_add;
        inline int top(int time)
        {
            return this->top_plus_time - time;
        }
        void clear()
        {
            is_head = 0;
            tot_head = 0;
            this->top_plus_time = 0;
            add_for_ans = 0;
            tot_add = 0;
        }
    } a[mN];
    void getson(int x, int y, int k)
    {
        a[x].tree[k] = y;
        if (y)
            a[y].tree[2] = x;
    }
    int root, tot, lem, rim;
    splay_tree()
    {
        a[0].clear();
        root = 1;
        lem = 2;
        rim = 3;
        tot = 3;
        a[rim].top_plus_time = -1;
        a[rim].bottom = -1;
        a[lem].top_plus_time = oo;
        a[lem].bottom = oo;
        getson(root, lem, 1);
        getson(lem, rim, 1);
    }
    bool ir(int x)
    {
        if (a[a[x].tree[2]].tree[1] == x)
            return 1;
        else
            return 0;
    }
    void update(int x)
    {
        int l = a[x].tree[0], r = a[x].tree[1];
        a[x].tot_add = a[l].tot_add + a[l].add_for_ans + a[r].tot_add
                + a[r].add_for_ans;
        a[x].tot_head = a[l].tot_head + a[l].is_head + a[r].tot_head
                + a[r].is_head;
    }
    void rorate(int x)
    {
        int fa = a[x].tree[2], k = ir(x);
        getson(fa, a[x].tree[1 - k], k);
        getson(a[fa].tree[2], x, ir(fa));
        getson(x, fa, 1 - k);
        update(fa);
    }
    void splay(int x, int root)
    {
        int fa;
        if (x == root)
            return;
        while (a[x].tree[2] != root)
        {
            fa = a[x].tree[2];
            if (a[fa].tree[2] != root)
            {
                if (ir(x) == ir(fa))
                    rorate(fa);
                else
                    rorate(x);
            }
            rorate(x);
        }
        update(x);
    }
    int find_top(int top)
    {
        int now = a[root].tree[1], last_now = 0;
        while (1)
        {
            if (a[now].top_plus_time > top)
            {
                if (a[now].tree[1] == 0)
                    return now;
                last_now = now;
                now = a[now].tree[1];
            }
            else
            {
                if (a[now].tree[0] == 0)
                {
                    splay(now, root);
                    return last_now;
                }
                now = a[now].tree[0];
            }
        }
        itserror
        ;
        return 0;
    }
    int find_bt(int bot)
    {
        int now = a[root].tree[1], last_now;
        while (1)
        {
            if (a[now].bottom < bot)
            {
                if (a[now].tree[0] == 0)
                    return now;
                last_now = now;
                now = a[now].tree[0];
            }
            else
            {
                if (a[now].tree[1] == 0)
                    return last_now;
                now = a[now].tree[1];
            }
        }
        itserror
        ;
        return 0;
    }
    void eraseall(int x)
    {
        if (x == 0)
            return;
        if (!exist[x])
            return;
        exist[x] = 0;
        if (a[x].tree[0])
            eraseall(a[x].tree[0]);
        if (a[x].tree[1])
            eraseall(a[x].tree[1]);
    }
    void refresh(int x, int time)
    {
        int fa = a[x].tree[2];
        a[x].is_head = 1;
        a[x].add_for_ans = a[x].top_plus_time - a[x].bottom;
        if (!ir(x))
        {
            if (a[fa].top(time) > a[x].bottom)
            {
                a[fa].awaytime = a[fa].top_plus_time - a[x].bottom;
                heap.push(handle(a[fa].awaytime, 2, fa, 0));
                a[fa].add_for_ans = a[x].bottom - a[fa].bottom;
                a[fa].is_head = 0;
 
            }
        }
        else
        {
            if (a[fa].bottom < a[x].top(time))
            {
                a[x].awaytime = a[x].top_plus_time - a[fa].bottom;
                heap.push(handle(a[x].awaytime, 2, x, 0));
                a[x].is_head = 0;
                a[x].add_for_ans = a[fa].bottom - a[x].bottom;
            }
        }
        rorate(x);
    }
    bool insert(int top, int bottom, int time)
    {
        int tp = find_top(top);
        splay(tp, root);
        if (a[tp].bottom <= bottom)
            return 0;
        int bt = find_bt(bottom);
        splay(bt, tp);
        if (a[bt].top_plus_time >= top)
            return 0;
        eraseall(a[bt].tree[0]);
        ++tot;
        a[tot].top_plus_time = top;
        a[tot].bottom = bottom;
        exist[tot] = 1;
        buf.time = top - bottom;
        buf.attr = 1;
        buf.argument1 = tot;
        heap.push(buf);
        getson(bt, tot, 0);
        refresh(tot, time);
        refresh(tot, time);
        splay(tot, root);
        return 1;
    }
    bool erase(int index)
    {
        if (exist[index])
        {
            int now = a[index].tree[0];
            if (now)
            {
                while (a[now].tree[1])
                    now = a[now].tree[1];
                splay(now, root);
            }
            getson(a[index].tree[2], a[index].tree[1], ir(index));
            splay(a[index].tree[2], root);
            exist[index] = 0;
            return 1;
        }
        return 0;
    }
    bool split(int index, int time)
    {
        if (exist[index] && a[index].awaytime == time)
        {
 
            a[index].is_head = 1;
            a[index].awaytime = -1;
            a[index].add_for_ans = a[index].top_plus_time - a[index].bottom;
            splay(index, root);
            return 1;
        }
        return 0;
    }
    void result(int time, int& len_, int& sev_)
    {
        splay(lem, root);
        splay(rim, lem);
        int now = a[rim].tree[0];
        if (now)
        {
            sev_ = a[now].tot_head + a[now].is_head;
            len_ = (a[now].tot_add + a[now].add_for_ans) - LL(sev_) * time;
        }
        else
        {
            len_ = 0;
            sev_ = 0;
        }
    }
    void log(int x)
    {
//      printf("id  %d  lson  %d  rson  %d  fa  %d\n",\
                x,a[x].tree[0],a[x].tree[1],a[x].tree[2]);
        if (a[x].tree[0])
            log(a[x].tree[0]);
        if (a[x].tree[1])
            log(a[x].tree[1]);
 
    }
} all;
 
bool operator <(const handle& a, const handle& b)
{
    return (b.time < a.time || (b.time == a.time && b.attr < a.attr));
}
;
 
LL ans;
 
inline bool hdl(const handle& buf)
{
    switch (buf.attr)
    {
    case 1:
        return all.erase(buf.argument1);
        break;
    case 2:
        return all.split(buf.argument1, buf.time);
        break;
    case 3:
        return all.insert(buf.argument1, buf.argument2, buf.time);
        break;
    default:
        itserror
        ;
    }
    itserror
    ;
    return 0;
}
 
int main()
{
    //freopen("/home/cad/input.txt", "r", stdin);
//  freopen("/home/cad/output.txt", "w", stdout);
    int n, x, y, d, last_time=-1, last_len, last_sev;
    scanf("%d\n", &n);
    for (int i = 0; i < n; i++)
    {
        scanf("%d%d%d", &x, &y, &d);
        if (d == 0)
            continue;
        buf.time = x;
        buf.attr = 3;
        buf.argument1 = y + d + x;
        buf.argument2 = y;
        heap.push(buf);
    }
    bool flag = 0;
    while (!heap.empty())
    {
        handle buf = heap.top();
        if (buf.time==5)
        {
            int x;
            x=x+1;
        }
        all.log(1);
//      cout<<"_____________________"<<buf.time<<"time"<<buf.attr<<"gao"<<buf.argument1<<"ans"<<buf.argument2<<endl;
 
        heap.pop();
        if (buf.time != last_time)
        {
            if (!flag)
                flag = 1;
            else
            {
                all.result(last_time, last_len, last_sev);
                ans += ((last_len << 1) - LL(buf.time - last_time) * last_sev)
                        * (buf.time - last_time);
//              printf("*************ans%lld\n",ans);
            }
            last_time = buf.time;
        }
        hdl(buf);
    }
    all.log(1);
    printf("%.1f\n", ans / 2.0);
    return 0;
}