[P9261] Płótno
模拟赛遇到的,好题。
给你一张 \(2\times n\) 的网格图,首尾相连,定义 \(val(l,r)(l\le r)\) 表示颜色编号在 \([l,r]\) 内的格子的四连通块数量,求 \(i\in [1,k],val(l,r)=i\) 的 \(l,r\) 的对数。
参考森林的联通块数量等于点数减边数,从小到大扫描 \(r\),用权值线段树维护 \(val(i,r)\),把 \([1,r]\) 区间加 \(1\) 表示加入一个点,把和 \(r\) 相邻的点 \(x\) 做 \([1,x]\) 区间减 \(1\) 表示增加一条边。
但这么胡乱加边肯定会出问题,有两种连出环的情况。
- 出现了一个 \(2\times 2\) 的连通块,会多出一条额外的边,把贡献加回来即可。
- 出现了一个首尾相连的大环,这时实际连通块数一定是 \(1\),但我们算出来会是 \(0\),在最后把 \(val=0\) 的答案加到 \(1\) 上去即可。
现在求区间 \(val=x(x\in [0,k])\) 的数量,说这个不能 \(\text{polylog}\) 纯尬黑啊,因为 \(k\) 只有 \(10\),维护一下区间 \(\min\) 和 \(\min\) 到 \(\min+k\) 的数量即可。
最后推荐一道很像的题 CF193D。
code
const int N = 5e5+55;
struct Node {
int mn,cnt[12];
Node() : mn(0) { memset(cnt,0,sizeof cnt); }
friend Node operator+(const Node &p,const Node &q) {
Node t{}; t.mn=min(p.mn,q.mn);
for(int i=p.mn;i<t.mn+12;i++) t.cnt[i-t.mn]+=p.cnt[i-p.mn];
for(int i=q.mn;i<t.mn+12;i++) t.cnt[i-t.mn]+=q.cnt[i-q.mn];
return t;
}
};
struct segment_tree {
#define mid ((L+R)>>1)
#define ls (u<<1)
#define rs (ls|1)
Node tr[N<<2]; int tag[N<<2];
void clac(int u,int k) { tr[u].mn+=k,tag[u]+=k; }
void pushdown(int u) {
if(tag[u]) clac(ls,tag[u]),clac(rs,tag[u]),tag[u]=0;
}
void build(int u,int L,int R) {
tag[u]=0,tr[u].mn=0,tr[u].cnt[0]=R-L;
if(R-L==1) return ;
build(ls,L,mid),build(rs,mid,R);
}
void update(int u,int L,int R,int l,int r,int k) {
if(l>=r) return ;
if(l<=L&&R<=r) return clac(u,k);
pushdown(u);
if(l<mid) update(ls,L,mid,l,r,k);
if(r>mid) update(rs,mid,R,l,r,k);
tr[u]=tr[ls]+tr[rs];
}
Node query(int u,int L,int R,int l,int r) {
if(l<=L&&R<=r) return tr[u];
pushdown(u);
if(r<=mid) return query(ls,L,mid,l,r);
if(l>=mid) return query(rs,mid,R,l,r);
return query(ls,L,mid,l,r)+query(rs,mid,R,l,r);
}
#undef mid
#undef ls
#undef rs
} T;
void Solve() {
int n,K; cin>>n>>K;
vv<int> a(2,vec<int>(n));
vec<pair<int,int>> pos(n<<1);
for(int i:{0,1}) for(int j=0;j<n;j++)
cin>>a[i][j],pos[--a[i][j]]={i,j};
vv<int> e(n<<1),q(n<<1);
for(int i=0;i<n;i++)
e[max(a[0][i],a[1][i])].push_back(min(a[0][i],a[1][i]));
for(int i=0;i<n-(n==2);i++) { int p=(i+1)%n;
e[max(a[0][i],a[0][p])].push_back(min(a[0][i],a[0][p]));
e[max(a[1][i],a[1][p])].push_back(min(a[1][i],a[1][p]));
q[max({a[0][i],a[1][i],a[0][p],a[1][p]})].
push_back(min({a[0][i],a[1][i],a[0][p],a[1][p]}));
}
T.build(1,0,n<<1);
vec<ll> ans(K);
auto upd = [&](int x,int k) { T.update(1,0,n<<1,0,x+1,k); };
for(int r=0;r<n<<1;r++) {
auto [x,y]=pos[r];
int lc=(y-1+n)%n,rc=(y+1)%n;
upd(r,1);
for(auto l:e[r]) upd(l,-1);
for(auto l:q[r]) upd(l,1);
auto now=T.query(1,0,n<<1,0,r+1);
for(int i=0;i<12&&now.mn+i<=K;i++) ans[max(1,now.mn+i)-1]+=now.cnt[i];
}
for(int i=0;i<K;i++) cout<<ans[i]<<' '; cout<<'\n';
}

浙公网安备 33010602011771号