卧薪尝胆,厚积薄发。
提高A组模拟 被单
Date: Mon Aug 13 11:24:16 CST 2018 In Category: NoCategory

Description:

平面上有 $n$ 个可覆盖但不相交的矩形,矩形不在边或端点上接触,有 $m$ 个点,每个点有颜色,询问每个矩形中包含多少颜色。
$1\le n,m\le80000$

Solution:

离散化 $+$ 线段树 $+$ 扫描线 $+set$ 启发式合并,做法就是求出每个点最上面包含它的矩形是谁,再求出每个点哪个矩形在他下面,假设矩形较小的在上面,这样可以建出一棵树,每个矩形维护一个 $set$ 表示颜色集合,最后在树上 $dfs$ 并把所有子树的 $set$ 启发式合并到这个点的 $set$ 上面,但不能真的 $dfs$ 会爆栈 $RE$ ,于是拓扑排序一下就行了,问题在于怎么求最开始的两个问题,先离散化 $y$ ,一边对 $x$ 扫描线一边维护一个标记永久化的线段树,在经过左边界时在线段树上区间覆盖,经过右边界时区间撤销,由于标记永久化了所以每个点开个栈压栈弹栈即可,在 $query$ 时一直到叶子节点选一个最晚的标记即可,这样就可以直接在线段树上求出每个点的覆盖矩形,求矩形的覆盖矩形直接选一个端点求点的覆盖矩形即可。

Code:


#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<vector>
#include<cctype>
#include<cstring>
using namespace std;
int n,m;
#define MAXN 80010
int yset[MAXN * 3],cnt = 0;
bool cmp_yset(int a,int b){return a < b;}
map<int,int> w;
struct line
{
int id,type;
int ytop,ybot;
double x;
}l[MAXN << 1];
bool cmp_x_line(line a,line b){return a.x < b.x;}
struct point
{
int y,col;
double x;
}p[MAXN];
bool cmp_x_point(point a,point b){return a.x < b.x;}
set<int> c[MAXN];
vector<int> g[MAXN];
int roots[MAXN];
int ans[MAXN];
struct node
{
int lc,rc;
stack< pair<int,int> > v;
}t[MAXN * 3 * 2];
int ptr = 0;
int newnode(){return ++ptr;}
int root;
#define mid ((l + r) >> 1)
void build(int &rt,int l,int r)
{
rt = newnode();
if(l == r)return;
build(t[rt].lc,l,mid);
build(t[rt].rc,mid + 1,r);
return;
}
int cur = 0;
void tag(int rt,int L,int R,int k,int l,int r)
{
if(L <= l && r <= R)
{
t[rt].v.push(make_pair(k,++cur));
return;
}
if(L <= mid)tag(t[rt].lc,L,R,k,l,mid);
if(R > mid)tag(t[rt].rc,L,R,k,mid + 1,r);
return;
}
pair<int,int> query(int rt,int p,int l,int r)
{
if(l == r)
{
if(!t[rt].v.empty())return t[rt].v.top();
else return make_pair(0,0);
}
pair<int,int> res;
if(p <= mid)res = query(t[rt].lc,p,l,mid);
else res = query(t[rt].rc,p,mid + 1,r);
if(!t[rt].v.empty())return (res.second > t[rt].v.top().second ? res : t[rt].v.top());
else return res;
}
void reset(int rt,int L,int R,int l,int r)
{
if(L <= l && r <= R)
{
t[rt].v.pop();
return;
}
if(L <= mid)reset(t[rt].lc,L,R,l,mid);
if(R > mid)reset(t[rt].rc,L,R,mid + 1,r);
return;
}
int fa[MAXN];
inline int read()
{
register int res = 0;
register char c = getchar();
while(!isdigit(c))c = getchar();
while(isdigit(c))
{
res = (res << 1) + (res << 3) + (c ^ 48);
c = getchar();
}
return res;
}
int ind[MAXN];
int main()
{
// freopen("plahte.in","r",stdin);
// freopen("plahte.out","w",stdout);
scanf("%d%d",&n,&m);
register int a1,b1,a2,b2;
register int a,b;
for(register int i = 1;i <= n;++i)
{
//scanf("%d%d%d%d",&a1,&b1,&a2,&b2);
a1 = read();yset[++cnt] = b1 = read();a2 = read();yset[++cnt] = b2 = read();
a = i * 2 - 1,b = i * 2;
l[a].ytop = b2;l[a].ybot = b1;l[a].x = (double)a1 - 0.25;l[a].type = 1;l[a].id = i;
l[b].ytop = b2;l[b].ybot = b1;l[b].x = (double)a2 + 0.25;l[b].type = 0;l[b].id = i;
}
sort(l + 1,l + 2 * n + 1,cmp_x_line);
for(register int i = 1;i <= m;++i)
{
p[i].x = (double)read();yset[++cnt] = p[i].y = read();p[i].col = read();
}
sort(p + 1,p + 1 + m,cmp_x_point);
sort(yset + 1,yset + 1 + cnt,cmp_yset);
int tot = 0;
for(register int i = 1;i <= 2 * n + m;++i)if(i == 1 || yset[i] != yset[i - 1])w[yset[i]] = ++tot;
build(root,1,tot);
for(int i = 1;i <= n;++i)roots[i] = i;
int i,j;
for(i = 1,j = 1;i <= 2 * n && j <= m;)
if(l[i].x < p[j].x)
{
if(l[i].type)
{
fa[l[i].id] = query(root,w[l[i].ytop],1,tot).first;
++ind[fa[l[i].id]];
tag(root,w[l[i].ybot],w[l[i].ytop],l[i].id,1,tot);
}
else reset(root,w[l[i].ybot],w[l[i].ytop],1,tot);
++i;
}
else
{
c[query(root,w[p[j].y],1,tot).first].insert(p[j].col);
++j;
}
for(;i <= 2 * n;++i)
if(l[i].type)
{
fa[l[i].id] = query(root,w[l[i].ytop],1,tot).first;
++ind[fa[l[i].id]];
tag(root,w[l[i].ybot],w[l[i].ytop],l[i].id,1,tot);
}
else reset(root,w[l[i].ybot],w[l[i].ytop],1,tot);
queue<int> q;
for(int i = 1;i <= n;++i)
if(ind[i] == 0)
{
q.push(i);
ans[i] = c[i].size();
}
while(!q.empty())
{
int k = q.front();q.pop();
if(c[roots[fa[k]]].size() < c[roots[k]].size())swap(roots[fa[k]],roots[k]);
for(set<int>::iterator it = c[roots[k]].begin();it != c[roots[k]].end();++it)
{
c[roots[fa[k]]].insert(*it);
}
--ind[fa[k]];
if(ind[fa[k]] == 0)
{
ans[fa[k]] = c[roots[fa[k]]].size();
q.push(fa[k]);
}
}
for(int i = 1;i <= n;++i)printf("%d\n",ans[i]);
// fclose(stdin);
// fclose(stdout);
return 0;
}
Copyright © 2020 wjh15101051
ღゝ◡╹)ノ♡