题面很长,可往往真正有用的题意却没有这么长,例如说这么一句:
-
床单放在上面,使它们之间角或边不会互相接触, 边也不会相交,但他可能把较小的床单放在大的上面,或者一个完全覆盖另个。
从这句话中,我们可以看出,矩形是不会相交的,且只有包含关系。所以,我们仅需记录一个矩形的父亲为包含它的所有矩形中最小的那个,原图可由此化为一棵森林。
那么,我们怎么构造一个森林呢?我们这里有两种方法:
- 用扫描线,线段树处理y轴,每次找到一个矩形之后判断这个矩形的下边界是否合法,如不合法就倍增往其父亲走,直到合法。
- 对于y轴,我们建一棵标记永久化的线段树。扫到左边界时,直接把标记打到相应区间,直接覆盖。
构造出森林过后,我们就可以在此森林上进行线段树合并或者是set启发式合并即可。
#include#include #include #include #include #include<set> #include #include #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< 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"< 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; }