专栏文章

题解:P9261 [PA 2022] Płótno

P9261题解参与者 2已保存评论 1

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
1 条
当前快照
1 份
快照标识符
@miq7eh8j
此快照首次捕获于
2025/12/04 00:10
3 个月前
此快照最后确认于
2025/12/04 00:10
3 个月前
查看原文

分析

要求联通块的数量,等价于求联通块的边界数量再除以 22,于是,我们考虑求边界对每个区间的贡献。由于行数只有 22,所以我们可以简单分讨下边界的形态(令红色为一定在区间中的格子,蓝色为一定不在区间中的格子,白色为我们不关心的格子):
第一种是边界只有一个格子,有上下左右四种对称情况。
第二种是边界有两个格子,有左右两种对称情况。
显然能使一个边界的区间一定满足 ll 在一段区间内,rr 在一段区间内,在二维平面上的影响就是矩形加,直接扫描线即可。要求权值为 1k1\sim k 的,直接在线段树上维护前 kk 小值即可,时间复杂度 O(nklogn)O(nk\log n)

代码

CPP
#include<bits/stdc++.h>
#define ll long long
#define pii pair<int,int>
#define fi first 
#define se second
using namespace std;
long long read(){
	long long x=0,f=1;char ch=getchar();
	while(!isdigit(ch))
	{if(ch=='-') f=-1;ch=getchar();}
	while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
	return x*f;
}
void write(long long x){
    if(x<0) putchar('-'),x=-x;
    if(x>9) write(x/10);
    putchar(x%10+'0');
}
const int N=2e5+10;
int n,k;
int b[2][N];
ll res[15];
struct oper{
	int l,r,v;
};
vector<oper>ad[N];
void add(int h,int i,int x,int i_){
	int l=1,r=2*n;
	if(b[h][i_]<x)l=max(l,b[h][i_]+1);
	else r=min(r,b[h][i_]-1);
	if(b[h^1][i]<x)l=max(l,b[h^1][i]+1);
	else r=min(r,b[h^1][i]-1);
    if(l>x||x>r)return;
	ad[l].push_back({x,r,1});
	ad[x+1].push_back({x,r,-1});
    // printf("insert h=%d i=%d x=%d i_=%d [%d,%d]\n",h,i,x,i_,l,r);
}
void add2(int i,int x,int y,int i_){
	int l=1,r=2*n;
	if(x>y)swap(x,y);
	if(b[0][i_]>=x&&b[0][i_]<=y)return;
	if(b[1][i_]>=x&&b[1][i_]<=y)return;
	if(b[0][i_]<x)l=max(l,b[0][i_]+1);
	else r=min(r,b[0][i_]-1);
	if(b[1][i_]<x)l=max(l,b[1][i_]+1);
	else r=min(r,b[1][i_]-1);
    if(l>x||y>r)return;
	ad[l].push_back({y,r,1});
	ad[x+1].push_back({y,r,-1});
}
#define pl p<<1
#define pr p<<1|1
struct Segment{
	struct Tree{
		pair<int,int>g[12];
		int tag;
		Tree(){for(int i=0;i<12;i++)g[i]={1e9,0};}
	}a[N<<2];
	void push(Tree &x,Tree y,Tree z){
		for(int i=0,p=0,q=0;i<=k;i++){
			if(y.g[p].fi==z.g[q].fi){
				x.g[i]=pii(y.g[p].fi,y.g[p].se+z.g[q].se);
				p++;q++;
			}
			else if(y.g[p].fi<z.g[q].fi){
				x.g[i]=y.g[p++];
			}
			else x.g[i]=z.g[q++];
		}
	}
	void pushup(int p){
		push(a[p],a[pl],a[pr]);
	}
	void pushdown(int p){
		if(a[p].tag){
			a[pl].tag+=a[p].tag;a[pr].tag+=a[p].tag;
			for(int i=0;i<12;i++){
				a[pl].g[i].fi+=a[p].tag;
				a[pr].g[i].fi+=a[p].tag;
			}
			a[p].tag=0;
		}
	}
	void build(int p,int L=1,int R=n*2){
		if(L==R){
			a[p].g[0]={0,1};return;
		}
		int mid=(L+R)>>1;
		build(pl,L,mid);build(pr,mid+1,R);
		pushup(p);
	}
	void change(int p,int l,int r,int v,int L=1,int R=2*n){
		if(l<=L&&R<=r){
			a[p].tag+=v;
			for(int i=0;i<12;i++){
				a[p].g[i].fi+=v;
			}
			return;
		}
        pushdown(p);
		int mid=(L+R)>>1;
		if(l<=mid)change(pl,l,r,v,L,mid);
		if(r>mid)change(pr,l,r,v,mid+1,R);
		pushup(p);
	}
}tr;
int main(){
	//freopen(".in","r",stdin);
	//freopen(".out","w",stdout);
	n=read();k=read();
	for(int i=0;i<n;i++){
		b[0][i]=read();
	}
	for(int i=0;i<n;i++){
		b[1][i]=read();
	}
	for(int i=0;i<n;i++){
		add(0,i,b[0][i],(i-1+n)%n);
		add(0,i,b[0][i],(i+1+n)%n);
		add(1,i,b[1][i],(i-1+n)%n);
		add(1,i,b[1][i],(i+1+n)%n);
		add2(i,b[0][i],b[1][i],(i-1+n)%n);
		add2(i,b[0][i],b[1][i],(i+1+n)%n);
	}
    tr.build(1);
	for(int i=1;i<=2*n;i++){
		for(auto u:ad[i])
			tr.change(1,u.l,u.r,u.v);
		for(int j=0;j<12;j++)
			if(tr.a[1].g[j].fi/2<=k)
				res[tr.a[1].g[j].fi/2]+=tr.a[1].g[j].se;
	}
    res[1]+=res[0]-1ll*(2*n)*(n*2-1)/2;
	for(int i=1;i<=k;i++)
		printf("%lld ",res[i]);
	puts("");
	return 0;
}

评论

1 条评论,欢迎与作者交流。

正在加载评论...