sgu-319-Kalevich Strikes Back-线段树

线段树记录当前区间是哪一个长方形在覆盖。

然后根据每一条线更新线段树。

如果是左边的边,那么把区间更新成当前长方形。

否则,把区间更新成当前长方形的前驱。

#include<stdio.h>
#include<iostream>
#include<stdlib.h>
#include<string.h>
#include<algorithm>
#include<vector>
#include<math.h>
#include<map>
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
#define maxn 130000
#define mem(a,b) (memset(a),b,sizeof(a))
#define lmin 1
#define rmax len
#define lson l,(l+r)/2,rt<<1
#define rson (l+r)/2+1,r,rt<<1|1
#define root lmin,rmax,1
#define now l,r,rt
#define int_now int l,int r,int rt
#define INF 99999999
#define LL __int64
#define mod 10007
#define eps 1e-6
#define zero(x) (fabs(x)<eps?0:x)
struct list
{
    int x;
    int y,yy;
    int id;
    friend bool operator <(const list &a,const list &b)
    {
       return a.x<b.x;
    }
}line[maxn];
int cover[maxn*4];
int pre[maxn];
LL all[maxn];
vector<int>vec[maxn];
map<int,int>mp;
int du[maxn];
int len;
void creat()
{
    memset(cover,0,sizeof(cover));
}
void push_down(int_now)
{
    if(cover[rt]!=-1)
    {
        cover[rt<<1]=cover[rt<<1|1]=cover[rt];
        cover[rt]=-1;
    }
}
void updata(int ll,int rr,int x,int_now)
{
    if(ll>r||rr<l)return;
    if(ll<=l&&rr>=r)
    {
        if(x<0) cover[rt]=pre[-x];
        else cover[rt]=x;
        return;
    }
    push_down(now);
    updata(ll,rr,x,lson);
    updata(ll,rr,x,rson);
}
int query(int ll,int rr,int_now)
{
    if(ll>r||rr<l)return -1;
    if(cover[rt]!=-1)return cover[rt];
    push_down(now);
    int x=-1;
    x=query(ll,rr,lson);
    if(x==-1)x=query(ll,rr,rson);
    return x;
}
void dfs(int x)
{
    for(int i=0;i<vec[x].size();i++)
    {
        all[x]-=all[vec[x][i]];
        dfs(vec[x][i]);
    }
}
int main()
{
    int n;
    LL W,H,x,xx,y,yy;
    while(~scanf("%d",&n))
    {
        mp.clear();
        scanf("%I64d%I64d",&W,&H);
        int ls=0;
        len=0;
        du[0]=-1;
        vec[0].clear();
        all[0]=(LL)W*H;
        for(int i=1;i<=n;i++)
        {
            vec[i].clear();
            scanf("%I64d%I64d%I64d%I64d",&x,&y,&xx,&yy);
            if(x>xx)swap(x,xx);
            if(y>yy)swap(y,yy);
            all[i]=(LL)(xx-x)*(yy-y);
            line[i*2-1].x=x;line[i*2-1].id=i;
            line[i*2-1].y=y;line[i*2-1].yy=yy;
            line[i*2].x=xx;line[i*2].id=-i;
            line[i*2].y=y;line[i*2].yy=yy;
            du[++ls]=y;
            du[++ls]=yy;
        }
        sort(du+1,du+ls+1);
        sort(line+1,line+n*2+1);
        for(int i=1;i<=ls;i++)
        {
            if(du[i]!=du[i-1])
            {
                mp[du[i]]=++len;
                du[len]=du[i];
            }
        }
        len--;
        creat();
        for(int i=1;i<=n*2;i++)
        {
            int l=mp[line[i].y];
            int r=mp[line[i].yy];
            if(line[i].id>0)
            {
                int x=query(l,r-1,root);
                pre[line[i].id]=x;
                vec[x].push_back(line[i].id);
            }
            updata(l,r-1,line[i].id,root);
        }
        dfs(0);
        sort(all,all+n+1);
        for(int i=0;i<=n;i++)
        {
            printf("%I64d",all[i]);
            if(i!=n)printf(" ");
            else printf("\n");
        }
    }
    return 0;
}

sgu-319-Kalevich Strikes Back-线段树

时间: 2024-11-05 15:00:23

sgu-319-Kalevich Strikes Back-线段树的相关文章

SGU 319 Kalevich Strikes Back(线段树扫描线)

题目大意: n个矩形,将一个大矩形分成 n+1 块.矩形之间不重合,可是包括.求这n+1个矩形的面积 思路分析: 用线段树记录他们之间的父子关系.然后dfs 计算面积. 当给出的矩形上边的时候,就要记录到该矩形的父亲去. #include <cstdio> #include <iostream> #include <cstring> #include <algorithm> #define lson num<<1,s,mid #define rs

sgu316Kalevich Strikes Back(线段树+扫描线)

做法:总体想法是求出一个矩形的面积以及它所包含的矩形,然后用自己的面积减掉所包含的.主要问题是怎样求解它所包含的矩形. 因为是没有相交点的,可以利用扫描线的方法去做,类似染色,当前段如果是x色,也就是第x个矩形,那么再把他染成y颜色时,说明x包含y,而当扫到y的上边时,这一段又恢复到x色.标记一下被包含的矩形,记录所包含的矩形. 因为会有恢复染色操作,up需要时时更新,左儿子和右儿子一样颜色时就可以合并为一段. 1 ; 2 } 3 void down(int w) 4 { 5 if(s[w]!=

sgu Kalevich Strikes Back

这道题就是求一个大矩形被n个矩形划分成n+1个部分的面积,这些矩形之间不会相交,可能包含.. 1 #include <cstdio> 2 #include <cstring> 3 #include <vector> 4 #include <algorithm> 5 #define maxn 120100 6 using namespace std; 7 8 long long s[maxn]; 9 vector<int>g[maxn]; 10 i

SGU - 311 Ice-cream Tycoon(线段树)

Description You've recently started an ice-cream business in a local school. During a day you have many suppliers delivering the ice-cream for you, and many students buying it from you. You are not allowed to set the prices, as you are told the price

2016shenyang-1002-HDU5893-List wants to travel-树链剖分+线段树维护不同区间段个数

肯定先无脑树链剖分,然后线段树维护一段区间不同个数,再维护一个左右端点的费用. 线段树更新,pushDown,pushUp的时候要注意考虑链接位置的费用是否相同 还有就是树链剖分操作的时候,维护上一个更新的位置的费用. 总之就是出现区间合并,就考虑总数是否要减一 好想不好写 //场上根本写不完啊 1 /*--------------------------------------------------------------------------------------*/ 2 3 #inc

[poj2104]可持久化线段树入门题(主席树)

解题关键:离线求区间第k小,主席树的经典裸题: 对主席树的理解:主席树维护的是一段序列中某个数字出现的次数,所以需要预先离散化,最好使用vector的erase和unique函数,很方便:如果求整段序列的第k小,我们会想到离散化二分和线段树的做法, 而主席树只是保存了序列的前缀和,排序之后,对序列的前缀分别做线段树,具有差分的性质,因此可以求任意区间的第k小,如果主席树维护索引,只需要求出某个数字在主席树中的位置,即为sort之后v中的索引:若要求第k大,建树时反向排序即可 1 #include

【BZOJ4942】[Noi2017]整数 线段树+DFS(卡过)

[BZOJ4942][Noi2017]整数 题目描述去uoj 题解:如果只有加法,那么直接暴力即可...(因为1的数量最多nlogn个) 先考虑加法,比较显然的做法就是将A二进制分解成log位,然后依次更新这log位,如果最高位依然有进位,那么找到最高位后面的第一个0,将中间的所有1变成0,那个0变成1.这个显然要用到线段树,但是复杂度是nlog2n的,肯定过不去. 于是我在考场上yy了一下,这log位是连续的,我们每次都要花费log的时间去修改一个岂不是很浪费?我们可以先在线段树上找到这段区间

bzoj1798: [Ahoi2009]Seq 维护序列seq 线段树

题目传送门 这道题就是线段树 先传乘法标记再传加法 #include<cstdio> #include<cstring> #include<algorithm> #define LL long long using namespace std; const int M=400010; LL read(){ LL ans=0,f=1,c=getchar(); while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();}

Vijos P1066 弱弱的战壕【多解,线段树,暴力,树状数组】

弱弱的战壕 描述 永恒和mx正在玩一个即时战略游戏,名字嘛~~~~~~恕本人记性不好,忘了-_-b. mx在他的基地附近建立了n个战壕,每个战壕都是一个独立的作战单位,射程可以达到无限(“mx不赢定了?!?”永恒[email protected][email protected]). 但是,战壕有一个弱点,就是只能攻击它的左下方,说白了就是横纵坐标都不大于它的点(mx:“我的战壕为什么这么菜”ToT).这样,永恒就可以从别的地方进攻摧毁战壕,从而消灭mx的部队. 战壕都有一个保护范围,同它的攻击