线段树刷题计划(模板向)

首先说明一下本人线段树风格:

用结构体数组t来表示线段树,左子树为l,右子树为r,懒惰标记为lazy。

在更新和查询函数中,为了防止混淆,只传递更新/查询的区间l和r,当前树的编号p,以及更新的值x。树的左右结点就用t[p].l和t[p].r表示(为了防止混淆)。

另外两个函数分别记为push_up和push_down。

在区间修改的时候,这一段代码是比较容易混淆的,如果搞不清为什么的话就直接背下来吧~

ll mid = (t[p].l + t[p].r) / 2;
    if(l<=mid) res += ask(p<<1,l,r);
    if(r>mid) res += ask(p<<1|1,l,r);

打*的是比较好的题目

HDU1166 单点修改区间求和

题目链接

http://acm.hdu.edu.cn/showproblem.php?pid=1166

代码

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const int maxn = 200005;

inline void read(ll &x) {
    ll f=1;x=0;char s=getchar();
    while(s<'0'||s>'9') {if(s=='-')f=-1;s=getchar();}
    while(s>='0'&&s<='9') {x=x*10+s-'0';s=getchar();}
    x *= f;
}

struct SegementTree {
    ll l,r,data;    
} t[maxn*4];

ll a[maxn],T,n;
string s;

void build(ll p,ll l,ll r) {
    t[p].data = 0;
    t[p].l = l, t[p].r = r;
    if(l==r) {t[p].data=a[l]; return;}
    ll mid = (l+r) / 2;
    build(p<<1, l, mid);
    build(p<<1|1,mid+1,r);
    t[p].data = t[p<<1].data + t[p<<1|1].data; 
}

void update(ll p,ll x,ll v) {
    if(t[p].l==t[p].r) {t[p].data += v; return;}
    ll mid = (t[p].l + t[p].r) / 2;
    if(x<=mid) update(p<<1,x,v);
    else update(p<<1|1,x,v);
    t[p].data = t[p<<1].data + t[p<<1|1].data;
}

ll ask(ll p,ll l,ll r) {
    ll res = 0;
    if(l<=t[p].l && r>=t[p].r) return t[p].data;
    ll mid = (t[p].l + t[p].r) / 2;
    if(l<=mid) res += ask(p<<1,l,r);
    if(r>mid) res += ask(p<<1|1,l,r);
    return res;
}

int main() {
    read(T);
    for(int i=1;i<=T;i++) {
        printf("Case %d:\n", i);
        read(n);
        for(int i=1;i<=n;i++) read(a[i]);
        build(1,1,n);
        while(cin>>s) {
            ll i,j;
            if(s=="End") break;
            read(i), read(j);
            if(s=="Add") update(1,i,j);
            else if(s=="Sub") update(1,i,-j);
            else printf("%lld\n",ask(1,i,j));
        }
    }
    return 0;
}

HDU1754 单点修改区间最值

题目链接

http://acm.hdu.edu.cn/showproblem.php?pid=1754

代码

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const int maxn = 200005;

inline void read(ll &x) {
    ll f=1;x=0;char s=getchar();
    while(s<'0'||s>'9') {if(s=='-')f=-1;s=getchar();}
    while(s>='0'&&s<='9') {x=x*10+s-'0';s=getchar();}
    x *= f;
}

struct SegementTree {
    ll l,r,data;    
} t[maxn*4];

ll n,m,a[maxn];
string s;

void build(ll p,ll l,ll r) {
    t[p].data = 0;
    t[p].l = l, t[p].r = r;
    if(l==r) {t[p].data=a[l]; return;}
    ll mid = (l+r) / 2;
    build(p<<1, l, mid);
    build(p<<1|1,mid+1,r);
    t[p].data = max(t[p<<1].data , t[p<<1|1].data);
}

void update(ll p,ll x,ll v) {
    if(t[p].l==t[p].r) {t[p].data = v; return;}
    ll mid = (t[p].l + t[p].r) / 2;
    if(x<=mid) update(p<<1,x,v);
    else update(p<<1|1,x,v);
    t[p].data = max(t[p<<1].data , t[p<<1|1].data);
}

ll ask(ll p,ll l,ll r) {
    ll res = -1e9;
    if(l<=t[p].l && r>=t[p].r) return t[p].data;
    ll mid = (t[p].l + t[p].r) / 2;
    if(l<=mid) res = max(res,ask(p<<1,l,r));
    if(r>mid) res = max(res,ask(p<<1|1,l,r));
    return res;
}

int main() {
    while(~scanf("%lld%lld",&n,&m)) {
        for(int i=1;i<=n;i++) read(a[i]);
        build(1,1,n);
        for(ll i=0,l,r;i<m;i++) {
            cin >> s;
            read(l), read(r);
            if(s=="U") update(1,l,r);
            else printf("%lld\n",ask(1,l,r)); 
        }
    }
    return 0;
}


HDU1394 求循环数组逆序对

题目链接

http://acm.hdu.edu.cn/showproblem.php?pid=1394

题解

求逆序对很简单,就是遍历一遍i,求1~a[i]-1中间有多少数,然后再在a[i]上面+1就行了。

本题数组会出现循环,但是找规律可以发现,由于数组是一个n的全排列,所以当开头数a[1]放到末尾时,逆序对个数必然会减少a[1]个,然后增加n-(a[1]+1)个。

代码

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const int maxn = 200005;

inline void read(ll &x) {
    ll f=1;x=0;char s=getchar();
    while(s<'0'||s>'9') {if(s=='-')f=-1;s=getchar();}
    while(s>='0'&&s<='9') {x=x*10+s-'0';s=getchar();}
    x *= f;
}

struct SegementTree {
    ll l,r,data;    
} t[maxn*4];

ll a[maxn],T,n;
string s;

void build(ll p,ll l,ll r) {
    t[p].data = 0;
    t[p].l = l, t[p].r = r;
    if(l==r) {t[p].data=0; return;}
    ll mid = (l+r) / 2;
    build(p<<1, l, mid);
    build(p<<1|1,mid+1,r);
    t[p].data = t[p<<1].data + t[p<<1|1].data; 
}

void update(ll p,ll x,ll v) {
    if(t[p].l==t[p].r) {t[p].data += v; return;}
    ll mid = (t[p].l + t[p].r) / 2;
    if(x<=mid) update(p<<1,x,v);
    else update(p<<1|1,x,v);
    t[p].data = t[p<<1].data + t[p<<1|1].data;
}

ll ask(ll p,ll l,ll r) {
    ll res = 0;
    if(l<=t[p].l && r>=t[p].r) return t[p].data;
    ll mid = (t[p].l + t[p].r) / 2;
    if(l<=mid) res += ask(p<<1,l,r);
    if(r>mid) res += ask(p<<1|1,l,r);
    return res;
}

int main() {
    while(~scanf("%lld", &n)) {
        ll ans = 0;
        build(1,1,n);
        for(int i=1;i<=n;i++) read(a[i]),a[i]++;
        for(int i=n;i;i--) {
            ans += ask(1,1,a[i]-1);
            update(1,a[i],1);
        }
        ll res = ans;
        for(int i=1;i<=n;i++) {
            a[i]--;
            ans = ans - a[i] + n - (a[i] + 1);
            res = min(res,ans); 
        }
        printf("%lld\n", res);
    }
    return 0;
}


*HDU2795 区间求最大值的位置

题目链接

http://acm.hdu.edu.cn/showproblem.php?pid=2795

题目

给定一个 h ∗ w h*w hw的白板,要求往上面贴n张1*w[i]的海报,要求贴的海报尽量靠上,在最靠上的前提下尽量靠左。要求贴一张海报输出一下贴的的行的位置(从上向下从1开始编号)。

题解

线段树维护每一行的剩余长度,然后贴一张海报之前查询一下能贴在哪个位置,由于一定是能贴在具体的一行,所以是会细化到具体的叶子结点。

由于h的范围是1e9,但是可以看出最多只贴n张海报,而n的范围是1e6的,所以建树的时候右边界为min(h,n)即可。

代码


#include <bits/stdc++.h>
using namespace std;

const int maxn = 200005;
typedef long long ll;
struct SegementTree {
    ll l,r,data;
}t[maxn*4];

ll h,w,n;

inline void read(ll &x) {
    ll f=1;x=0;char s=getchar();
    while(s<'0'||s>'9') {if(s=='-')f=-1;s=getchar();}
    while(s>='0'&&s<='9') {x=x*10+s-'0';s=getchar();}
    x *= f;
}

void build(ll p,ll l,ll r) {
    t[p].l = l, t[p].r = r, t[p].data=0;
    if(l==r) {t[p].data=w; return;}
    ll mid = (l + r) / 2;
    build(p<<1,l,mid);
    build(p<<1|1,mid+1,r);
    t[p].data = max(t[p<<1].data,t[p<<1|1].data);
}

ll ask(ll p,ll x) {
    ll res = 0, l = t[p].l, r = t[p].r;
    if(l==r) {
        t[p].data -= x;
        return l;
    }
    if(x<=t[p<<1].data) res = ask(p<<1,x);
    else if(x<=t[p<<1|1].data) res = ask(p<<1|1,x);
    t[p].data = max(t[p<<1].data,t[p<<1|1].data);
    return res;
}

int main() {    
    while(~scanf("%lld%lld%lld",&h,&w,&n)) {
        ll temp = min(n,h);
        build(1,1,temp);
        while(n--) {
            ll x; 
            read(x);
            if(t[1].data>=x) {
                printf("%lld\n", ask(1,x));
            } else puts("-1");
        }
    }
    return 0;
}

HDU1698 区间替换区间求和

题目链接

http://acm.hdu.edu.cn/showproblem.php?pid=1698

代码

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const int maxn = 200005;

inline void read(ll &x) {
    ll f=1;x=0;char s=getchar();
    while(s<'0'||s>'9') {if(s=='-')f=-1;s=getchar();}
    while(s>='0'&&s<='9') {x=x*10+s-'0';s=getchar();}
    x *= f;
}

struct SegementTree {
    ll l,r,data,lazy;    
} t[maxn*4];

ll a[maxn],T,n,q,maxi;
string s;

void build(ll p,ll l,ll r) {
    t[p].data = t[p].lazy = 0;
    t[p].l = l, t[p].r = r;
    if(l==r) {t[p].data=1; return;}
    ll mid = (l+r) / 2;
    build(p<<1, l, mid);
    build(p<<1|1,mid+1,r);
    t[p].data = t[p<<1].data + t[p<<1|1].data;
}

void push_down(ll p) {
    if(t[p].lazy) {
        t[p<<1].data = t[p].lazy * (t[p<<1].r - t[p<<1].l + 1);
        t[p<<1|1].data = t[p].lazy * (t[p<<1|1].r - t[p<<1|1].l + 1);
        t[p<<1].lazy = t[p<<1|1].lazy = t[p].lazy;
        t[p].lazy = 0;
    }
}

void update(ll p,ll l,ll r,ll x) {
    if(l<=t[p].l && r>=t[p].r) {
        t[p].data = x*(t[p].r-t[p].l+1);
        t[p].lazy = x;
        return;
    }
    push_down(p);
    ll mid = (t[p].l + t[p].r) / 2;
    if(l<=mid) update(p<<1,l,r,x);
    if(r>mid) update(p<<1|1,l,r,x);
    t[p].data = t[p<<1].data + t[p<<1|1].data;
}

int main() {
    read(T);
    for(int cnt=1;cnt<=T;cnt++) {
        read(n);
        build(1,1,n);
        read(q);
        while(q--) {
            ll x,y,z;
            read(x), read(y), read(z);
            update(1,x,y,z);
        }
        // for(int i=1;i<=30;i++) cout << t[i].data << endl;
        printf("Case %lld: The total value of the hook is %lld.\n",cnt,t[1].data);
    }
    return 0;
}


POJ3468 区间增减区间求和

题目链接

https://cn.vjudge.net/contest/296742#problem/F

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
using namespace std;

const int maxn = 200005;
typedef long long ll;
struct SegementTree {
    ll l,r,data,lazy;
}t[maxn*4];

ll h,w,n,a[maxn],q;
string s;

inline void read(ll &x) {
    ll f=1;x=0;char s=getchar();
    while(s<'0'||s>'9') {if(s=='-')f=-1;s=getchar();}
    while(s>='0'&&s<='9') {x=x*10+s-'0';s=getchar();}
    x *= f;
}

void push_down(ll p) {
    if(t[p].lazy) {
        t[p<<1].data += t[p].lazy * (t[p<<1].r - t[p<<1].l + 1);
        t[p<<1|1].data += t[p].lazy * (t[p<<1|1].r - t[p<<1|1].l + 1);
        t[p<<1].lazy += t[p].lazy;
        t[p<<1|1].lazy += t[p].lazy;
        t[p].lazy = 0;
    }
}

void build(ll p,ll l,ll r) {
    t[p].l = l, t[p].r = r, t[p].data = t[p].lazy = 0;
    if(l==r) {t[p].data=a[l];return;}
    ll mid = (l+r) / 2;
    build(p<<1,l,mid);
    build(p<<1|1,mid+1,r);
    t[p].data = t[p<<1].data + t[p<<1|1].data;
}

void update(ll p,ll l,ll r,ll x) {
    if(l<=t[p].l && r>=t[p].r) {
        t[p].data += x * (t[p].r - t[p].l + 1);
        t[p].lazy += x;
        return;
    }
    push_down(p);
    ll mid = (t[p].l + t[p].r) / 2;
    if(l<=mid) update(p<<1,l,r,x);
    if(r>mid) update(p<<1|1,l,r,x);
    t[p].data = t[p<<1].data + t[p<<1|1].data;
}

ll ask(ll p,ll l,ll r) {
    ll res = 0;
    if(l<=t[p].l && r>=t[p].r) return t[p].data;
    push_down(p);
    ll mid = (t[p].l + t[p].r) / 2;
    if(l<=mid) res += ask(p<<1,l,r);
    if(r>mid) res += ask(p<<1|1,l,r);
    return res;
}

int main() {
    read(n), read(q);
    for(int i=1;i<=n;i++) read(a[i]);
    build(1,1,n);
    while(q--) {
        cin >> s;
        if(s=="C") {
            ll x,y,z;
            read(x), read(y), read(z);
            update(1,x,y,z);
        } else {
            ll x,y;
            read(x), read(y);
            printf("%lld\n",ask(1,x,y));
        }
    }
    return 0;
}

*POJ2528 离散化+成段替换+区间查询

题目链接

http://poj.org/problem?id=2528

题目

给定一个长度为n的白板,往上面贴海报。
每次给出海报所覆盖的区间[L,R],要求出最后露在外面的海报的张数。

题解

由于本题数据过大,需要离散化。
离散化后将每张海报编号,查询的时候由于只查找一次,所以就细化到每个叶子结点,统计有多少个不同的编号。

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;

typedef long long ll;
const int maxn = 100005;

inline void read(ll &x) {
    ll f=1;x=0;char s=getchar();
    while(s<'0'||s>'9') {if(s=='-')f=-1;s=getchar();}
    while(s>='0'&&s<='9') {x=x*10+s-'0';s=getchar();}
    x *= f;
}

struct SegementTree {
    ll l,r,data,lazy;
}t[maxn*4];

ll n,x,y,cnt,m,a[maxn],T,b[maxn],ans;
bool vis[20005];
vector<pair<ll,ll> >e;

void build(ll p,ll l,ll r) {
    t[p].l = l, t[p].r = r, t[p].data = t[p].lazy = 0;
    if(l==r) {t[p].lazy=-1;return;}
    ll mid = (l+r) / 2;
    build(p<<1,l,mid);
    build(p<<1|1,mid+1,r);
}

void push_down(ll p) {
    if(t[p].lazy) {
        t[p<<1].data = t[p<<1|1].data = t[p].data;
        t[p<<1].lazy = t[p<<1|1].lazy = t[p].lazy;
        t[p].lazy = 0;
    }
}

void update(ll p,ll l,ll r,ll x) {
    // cout << p<<' ' <<t[p].l<<' ' << t[p].r << ' '<< l << ' ' << r << endl;
    if(l<=t[p].l && r>=t[p].r) {t[p].data = t[p].lazy =x;return;}
    push_down(p);
    ll mid = (t[p].l + t[p].r) / 2;
    if(l<=mid) update(p<<1,l,r,x);
    if(r>mid) update(p<<1|1,l,r,x);
}

void ask(ll p,ll l,ll r) {
    if(t[p].l==t[p].r) {
        if(!vis[t[p].data]) {
            vis[t[p].data] = 1;
            ans++;
        } 
        return ;
    }
    push_down(p);
    ll mid = (t[p].l + t[p].r) / 2;
    if(l<=mid) ask(p<<1,l,r);
    if(r>mid) ask(p<<1|1,l,r);
}

void discrete() {
    sort(a,a+cnt);
    b[m++] = a[0];
    for(int i=1;i<cnt;i++) {
        if(a[i]!=a[i-1]) b[m++]=a[i];
    }
}

ll query(ll x) {
    return lower_bound(b,b+m,x)-b;
}

int main() {
    read(T);
    while(T--) {
        memset(vis,0,sizeof(vis));
        cnt = m = ans = 0;
        e.clear();
        read(n);
        for(int i=0;i<n;i++) {
            read(x), read(y);
            a[cnt++] = x;
            a[cnt++] = y;
            e.push_back(make_pair(x,y));
        }
        discrete();
        build(1,1,m);
        for(int i=0;i<n;i++) {
            x = e[i].first, y = e[i].second;
            x = query(x)+1, y = query(y)+1;
            // cout << x << ' ' << y << endl;
            update(1,x,y,i+1);
        }
        ask(1,1,m);
        cout << ans << endl;
    }
    return 0;
}

*POJ3367 区间合并

题目链接

http://poj.org/problem?id=3667

题目

给定一个长长的旅馆,里面有n间连续的屋子。
再给出m个询问,每次要么要求住进来a[i]个人(他们必须住连续的房间)
或者让[L,R]区间的人离开(允许屋子本来就是空的)

题解

线段树维护每个屋子是否住了人,标记为0/1。住人进来的时候,先查询从哪个结点开始连续的一段没有人,然后在更新这一段。

而查询的过程就略显麻烦,需要维护三个值,lsum表示从最左边开始连续的空房间数量,rsum表示从右边开始连续的空房间数量,sum表示整段中连续的空房间数量。这三个关系的维护(即push_up函数)是本体的一个难点。

代码

#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#include <cstdio>
using namespace std;

typedef long long ll;
const int maxn = 50005;

inline void read(ll &x) {
    ll f=1;x=0;char s=getchar();
    while(s<'0'||s>'9') {if(s=='-')f=-1;s=getchar();}
    while(s>='0'&&s<='9') {x=x*10+s-'0';s=getchar();}
    x *= f;
}

struct SegementTree {
    ll l,r,lsum,rsum,sum,lazy;
}t[maxn*4];

ll n,m;

void build(ll p,ll l,ll r) {
    t[p].l = l, t[p].r = r;
    t[p].lsum = t[p].rsum = t[p].sum = r-l+1;
    t[p].lazy = -1; //懒惰标记初始为-1
    if(l==r) {t[p].sum = 1;return;}
    ll mid = (l+r) / 2;
    build(p<<1,l,mid);
    build(p<<1|1,mid+1,r);
}

void push_down(ll p) {
    if(t[p].lazy!=-1) { //0的话表示走人,所以这一段的空房间数量=区间长度
        t[p<<1].lsum = t[p<<1].rsum = t[p<<1].sum = t[p].lazy ? 0 : t[p<<1].r-t[p<<1].l+1;
        t[p<<1|1].lsum = t[p<<1|1].rsum = t[p<<1|1].sum = t[p].lazy ? 0 : t[p<<1|1].r-t[p<<1|1].l+1;
        t[p<<1].lazy = t[p<<1|1].lazy = t[p].lazy;
        t[p].lazy = -1;
    }
}

void push_up(ll p) {
    t[p].lsum = t[p<<1].lsum;
    t[p].rsum = t[p<<1|1].rsum;
    ll k = t[p].r - t[p].l + 1;
    if(t[p<<1].lsum==t[p<<1].r-t[p<<1].l+1) t[p].lsum += t[p<<1|1].lsum;
    if(t[p<<1|1].rsum==t[p<<1|1].r-t[p<<1|1].l+1) t[p].rsum += t[p<<1].rsum;
    t[p].sum = max(t[p<<1].rsum+t[p<<1|1].lsum,max(t[p<<1].sum,t[p<<1|1].sum));
}

void update(ll p,ll l,ll r,ll x) {
    if(l<=t[p].l && r>=t[p].r) {
        if(x) 
            t[p].lsum = t[p].rsum = t[p].sum = 0;
        else 
            t[p].lsum = t[p].rsum = t[p].sum = t[p].r - t[p].l + 1;
        t[p].lazy = x;
        return;
    }
    push_down(p);
    ll mid = (t[p].l+t[p].r) / 2;
    if(l<=mid) update(p<<1,l,r,x);
    if(r>mid) update(p<<1|1,l,r,x);
    push_up(p);
}

ll ask(ll p,ll x) {
    if(t[p].l==t[p].r) return 1;
    push_down(p);
    ll mid = (t[p].l + t[p].r) / 2;
    if(t[p<<1].sum >= x) return ask(p<<1,x);
    else if(t[p<<1].rsum + t[p<<1|1].lsum >= x) return mid-t[p<<1].rsum+1;
    else return ask(p<<1|1,x);
}

int main() {
    read(n), read(m);
    build(1,1,n);
    for(ll i=0,f,x,y;i<m;i++) {
        read(f);
        if(f==1) {
            read(x);
            if(t[1].sum < x) {puts("0");continue;}
            ll pos = ask(1,x);
            printf("%lld\n",pos);
            update(1,pos,pos+x-1,1);
        } else {
            read(x), read(y);
            update(1,x,x+y-1,0);
        }
    }
    return 0;
}

*HDU1542 扫描线求矩形面积并

题目链接

http://acm.hdu.edu.cn/showproblem.php?pid=1542

题目

给定n个矩形,要求它们面积的并集。

题解

用扫描线来做。
关于扫描线,我觉得这一篇博客讲的不错https://blog.csdn.net/xianpingping/article/details/83032798?tdsourcetag=s_pcqq_aiomsg
所谓扫描线,就是对于一个矩形,只维护竖着的两条边,这样横着的两条边就可以看作两条扫描线,从下向上扫描,在遇到矩形的下底边时,给这个区间的cnt+1,表示当前有至少一条边,当遇到上底边的时候就-1,减到0的时候该边就不存在了。每次用 两个扫描线的距离* 当前所有扫描线投影到x轴的长度 表示矩形的面积。

本题由于坐标都是浮点数,所以对于x坐标先离散化一下(by数组b),然后用线段树维护,线段树的每个叶子结点x维护的是从[b[x],b[x+1]]的这个区间的长度,所以更新的区间离散化后记为L和R,那么R应该-1(因为维护的最右边刚刚够到R点的位置,却不能加上它维护的那个区间),而在统计的时候累加结果应该用b[r+1]-b[l],因为b[r+1]所在的位置正好是b[r]维护区间的右端点。

代码

#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <string>
#include <vector>
using namespace std;

const int maxn = 200005;

struct node {
    double l, r, h;
    int d;
    node() {}
    node(double l, double r, double h, int d) : l(l), r(r), h(h), d(d) {}
    bool operator<(const node &b) const { return h < b.h; }
};

struct SegementTree {
    int l, r, cnt;
    double sum;
} t[maxn * 4];

vector<node> e;
vector<double> s;
double b[maxn];
int n, m, num;

void discrete() {
    sort(e.begin(), e.end());
    sort(s.begin(), s.end());
    b[++m] = s[0];
    for (int i = 1; i < s.size(); i++) {
        if (s[i] != s[i - 1]) b[++m] = s[i];
    }
}

int query(double x) { return lower_bound(b + 1, b + m + 1, x) - b; }

void push_up(int p) {
    if (t[p].cnt) {
        t[p].sum = b[t[p].r + 1] - b[t[p].l];
    } else if (t[p].l == t[p].r) 
        t[p].sum = 0;
    else
        t[p].sum = t[p << 1].sum + t[p << 1 | 1].sum;
}

void build(int p, int l, int r) {
    t[p].l = l, t[p].r = r;
    t[p].sum = t[p].cnt = 0;
    if (l == r) {
        return;
    }
    int mid = (l + r) / 2;
    build(p << 1, l, mid);
    build(p << 1 | 1, mid + 1, r);
    push_up(p);
}

void update(int p, int l, int r, int x) {
    if (l <= t[p].l && r >= t[p].r) {
        t[p].cnt += x;
        push_up(p);
        return;
    }
    int mid = (t[p].l + t[p].r) / 2;
    if (l <= mid) update(p << 1, l, r, x);
    if (r > mid) update(p << 1 | 1, l, r, x);
    push_up(p);
}

int main() {
    while (cin>>n) {
    	if(!n) break;
        double a1, b1, a2, b2, ans = 0;
        m = 0;
        e.clear();
        s.clear();
        for (int i = 0; i < n; i++) {
            cin >> a1 >> b1 >> a2 >> b2;
            e.push_back(node(a1, a2, b1, 1));
            s.push_back(a1);
            e.push_back(node(a1, a2, b2, -1));
            s.push_back(a2);
        }
        discrete();
        build(1, 1, m);
        for (int i = 0; i < e.size() - 1; i++) {
            int l = query(e[i].l), r = query(e[i].r) - 1;
            update(1, l, r, e[i].d);
            if (i != e.size() - 1) ans += t[1].sum * (e[i + 1].h - e[i].h);
        }
        printf("Test case #%d\nTotal explored area: %.2f\n\n", ++num, ans);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

总想玩世不恭

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值