题面很长,可往往真正有用的题意却没有这么长,例如说这么一句:
-
床单放在上面,使它们之间角或边不会互相接触, 边也不会相交,但他可能把较小的床单放在大的上面,或者一个完全覆盖另个。
从这句话中,我们可以看出,矩形是不会相交的,且只有包含关系。所以,我们仅需记录一个矩形的父亲为包含它的所有矩形中最小的那个,原图可由此化为一棵森林。
那么,我们怎么构造一个森林呢?我们这里有两种方法:
- 用扫描线,线段树处理y轴,每次找到一个矩形之后判断这个矩形的下边界是否合法,如不合法就倍增往其父亲走,直到合法。
- 对于y轴,我们建一棵标记永久化的线段树。扫到左边界时,直接把标记打到相应区间,直接覆盖。
构造出森林过后,我们就可以在此森林上进行线段树合并或者是set启发式合并即可。
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<set> #include<queue> #include<ctime> #define MAXN 200005 #define ll long long #define maxn 15 #define maxs 1000005 #define inf 1e9 #define eps 1e-9 using namespace std; inline char gc() {static char now[1<<16],*S,*T;if (T==S) {T=(S=now)+fread(now,1,1<<16,stdin);if (T==S) return EOF;}return *S++; } inline ll readlong() {ll x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9') {x*=10;x+=ch-'0';ch=getchar();}return x*f; } inline int read() {int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9') {x*=10;x+=ch-'0';ch=getchar();}return x*f; } void putint(long long t) {int ans[40]= {0};for(; t; t/=10)ans[++ans[0]]=t%10;for(; ans[0]; ans[0]--)putchar('0'+ans[ans[0]]);putchar('\n'); } const int N=500005; int n,m; struct edge{int to,nxt; }e[N]; int h[N],cnt; void add(int x,int y){ // cout<<x<<' '<<y;e[++cnt]=(edge){y,h[x]};h[x]=cnt; } int pre[N],_k[N],_y[N],rt[N]; int ans[N]; int dx,dy,dv; int g[N<<5]; int col[N<<5],f[N<<5][2]; int cntt,cnty,cnts; int tot; struct bed{int x,y,k,i;bool operator <(const bed &a)const{if(x==a.x){return i>a.i;}return x<a.x;} }mp[N<<2]; int query(int x,int l,int r){if(g[x]>=0||l==r){return g[x];}if(!x){return 0;}int mid=(l+r)>>1;if(dx<=mid){return query(x<<1,l,mid);}else{return query(x<<1|1,mid+1,r);} } void push(int x){if(g[x]<0){return ;}g[x<<1]=g[x<<1|1]=g[x];g[x]=-1; } void modify(int x,int l,int r){ // cout<<"Asdf"<<endl;if(dx<=l&&dy>=r){g[x]=dv;return ;}push(x);int mid=(l+r)>>1;if(dx<=mid){modify(x<<1,l,mid);}if(dy>mid){modify(x<<1|1,mid+1,r);} } void add_cor(int &x,int l,int r){if(!x){x=++tot;}if(l==r){col[x]=1;return;}int mid=(l+r)>>1;if(dx<=mid){add_cor(f[x][0],l,mid);}else{add_cor(f[x][1],mid+1,r);}col[x]=col[f[x][0]]+col[f[x][1]]; } int merge(int a,int b,int l,int r){if(!a|!b){return a^b;}if(l==r){return a;}int mid=(l+r)>>1;f[a][0]=merge(f[a][0],f[b][0],l,mid);f[a][1]=merge(f[a][1],f[b][1],mid+1,r);col[a]=col[f[a][0]]+col[f[a][1]];return a; } void dfs(int x){for(int i=h[x];i;i=e[i].nxt){int y=e[i].to;if(y!=pre[x]){dfs(y);rt[x]=merge(rt[x],rt[y],1,cnts);}}ans[x]=col[rt[x]]; } int main(){memset(g,-1,sizeof(g));n=read();m=read();for(int i=1;i<=n;i++){int a=read();int b=read();int c=read();int d=read();mp[++cntt]=(bed){a,b,d,i};_y[++cnty]=b;mp[++cntt]=(bed){c,b,d,-i};_y[++cnty]=d;}for(int i=1;i<=m;i++){int x=read();int y=read();int k=read();mp[++cntt]=(bed){x,y,k,0};_y[++cnty]=y;_k[++cnts]=k;}sort(_y+1,_y+1+cnty);cnty=unique(_y+1,_y+1+cnty)-_y-1;sort(_k+1,_k+1+cnts);cnts=unique(_k+1,_k+1+cnts)-_k-1;sort(mp+1,mp+cntt+1);for(int i=1;i<=cntt;i++){mp[i].y=lower_bound(_y+1,_y+1+cnty,mp[i].y)-_y;if(mp[i].i){mp[i].k=lower_bound(_y+1,_y+1+cnty,mp[i].k)-_y;if(mp[i].i>0){dx=mp[i].y;dy=mp[i].k;dv=mp[i].i;if((pre[dv]=query(1,1,cnty))>0){add(pre[dv],dv);}modify(1,1,cnty);continue;}dx=mp[i].y;dy=mp[i].k;dv=max(pre[-mp[i].i],0);modify(1,1,cnty);continue;}mp[i].k=lower_bound(_k+1,_k+cnts+1,mp[i].k)-_k;dx=mp[i].y;int tmp=query(1,1,cnty);if(tmp>0){dx=mp[i].k;add_cor(rt[tmp],1,cnts);}}for(int i=1;i<=n;i++){if(pre[i]<=0){dfs(i);}}for(int i=1;i<=n;i++){printf("%d\n",ans[i]);}return 0; }