CF983D Arkady and Rectangles

题意:给你若干个不同色的矩形。问依次覆盖,最后留在平面上的有多少种颜色(要加上空白)?

n<=100000.

标程:

 1 #include<bits/stdc++.h>
 2 #define fir first
 3 #define sec second
 4 #define P pair<int,int>
 5 using namespace std;
 6 int read()
 7 {
 8    int x=0,f=1;char ch=getchar();
 9    while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();}
10    while (ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
11    return x*f;
12 }
13 const int N=200005;
14 set<int> s[N<<2]; 
15 vector<P> vec[N];
16 int Max[N<<2],Min[N<<2],vis[N],a[N],b[N],c[N],d[N],px[N],py[N],ans,tmp,n;
17 void up(int k,int l,int r)
18 {
19     if (l==r) Max[k]=Min[k]=0;
20     else Max[k]=max(Max[k<<1],Max[k<<1|1]),Min[k]=min(Min[k<<1],Min[k<<1|1]);//统计子节点
21     if ((int)s[k].size())//统计这个节点的覆盖
22     {
23         if (vis[tmp=*s[k].rbegin()]) Min[k]=max(Min[k],tmp);
24         else Max[k]=max(Max[k],tmp);
25     }
26     if (Max[k]<Min[k]) Max[k]=0;
27 }
28 void ins(int k,int l,int r,int L,int R,int x)
29 {
30     if (L<=l&&r<=R)
31     {
32         if (x)
33           if (x>0) s[k].insert(x);else s[k].erase(-x);
34         up(k,l,r);
35         return;
36     }
37     int mid=(l+r)>>1;
38     if (L<=mid) ins(k<<1,l,mid,L,R,x);
39     if (R>mid) ins(k<<1|1,mid+1,r,L,R,x);
40     up(k,l,r);
41 }
42 int main()
43 {
44    n=read();
45    for (int i=1;i<=n;i++) a[i]=read(),b[i]=read(),c[i]=read(),d[i]=read(),px[++*px]=a[i],px[++*px]=c[i],py[++*py]=b[i],py[++*py]=d[i];
46    sort(px+1,px+*px+1);sort(py+1,py+*py+1);
47    *px=unique(px+1,px+*px+1)-px-1;
48    *py=unique(py+1,py+*py+1)-py-1;
49    for (int i=1;i<=n;i++)
50    {
51        a[i]=lower_bound(px+1,px+*px+1,a[i])-px;
52        c[i]=lower_bound(px+1,px+*px+1,c[i])-px;
53        b[i]=lower_bound(py+1,py+*py+1,b[i])-py;
54        d[i]=lower_bound(py+1,py+*py+1,d[i])-py-1;
55        vec[a[i]].push_back(P(i,i));
56        vec[c[i]].push_back(P(i,-i));
57     }
58    for (int i=1;i<=*px;i++)
59    {
60        for (int j=0;j<vec[i].size();j++) ins(1,1,*py,b[vec[i][j].fir],d[vec[i][j].fir],vec[i][j].sec);
61        while (Max[1])
62        {
63            vis[Max[1]]=1;ans++;
64            ins(1,1,*py,b[Max[1]],d[Max[1]],0);
65         }
66     }
67     printf("%d\n",ans+1);
68    return 0;
69 }

 

易错点:1.对端点离散化的时候注意直接离散,不要先把d[i]-1。离散化寻址的时候再找前一个。(不然会错)

即是把边染色转换成点染色。

 

题解:线段树+set+技巧神题

很容易想到扫描线,问题是:1.如何不重复地统计出现过的颜色,2.如何用线段树快速维护颜色层的覆盖。

问题1用一个vis数组打标记,问题2对于线段树的每一个节点维护一个set,表示完全覆盖这个节点的颜色。

对于每一个节点所表示区间露出来的颜色,用Min表示统计过的最小覆盖颜色。Max表示未统计过最大覆盖颜色。(有性质Min和Max只有其一有值)

每次取Max[1]统计答案,并在线段树中消除该颜色的贡献。

转载于:https://www.cnblogs.com/Scx117/p/9069339.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值