Codeforces 811 E. Vladik and Entertaining Flags

Title Description

Portal

Main idea: Two blocks with common edges and the same color belong to the same connected block. Each time, how many connected blocks are asked in an interval.

Title Solution

Line Segment Tree + and Search
The basic idea is that because the number of rows is relatively small, the left and right columns of each interval can be maintained and collected.
Maintenance must ensure that the number of the two places that can be connected in the interval is the same.
When the two intervals are merged, the father of the left and right columns of the two intervals is assigned to himself. If the adjacent positions of the two intervals have the same color, they are merged by searching the set, and then the numbers of the left and right columns of the intervals are queried from the set.
That is to say, the left and right columns of each interval maintain the number of a connected block, which is merged by using and searching sets.
See the code for the specific process.

Code

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#define N 100003
using namespace std;
int L[N*4][12],R[N*4][12],sum[N*4],cnt,q;
int fa[N*10],a[12][N],n,m,ls[13],rs[13],ans;
bool pd=false;
int find(int x)
{
    if (fa[x]==x) return fa[x];
    fa[x]=find(fa[x]);
    return fa[x];
}
void update(int now,int l,int r)
{
    int mid=(l+r)/2;
    int ls=now<<1; int rs=now<<1|1;
    sum[now]=sum[ls]+sum[rs];
    for (int i=1;i<=n;i++) {
        fa[L[ls][i]]=L[ls][i];
        fa[L[rs][i]]=L[rs][i];
        fa[R[ls][i]]=R[ls][i];
        fa[R[rs][i]]=R[rs][i];
    }
    for (int i=1;i<=n;i++)
     if (a[i][mid]==a[i][mid+1]) {
        int r1=find(L[rs][i]); int r2=find(R[ls][i]);
        if (r1!=r2) {
            sum[now]--;
            fa[r2]=r1;
         }
     }
    for (int i=1;i<=n;i++) {
        L[now][i]=find(L[ls][i]);
        R[now][i]=find(R[rs][i]);
    }
}
void build(int now,int l,int r)
{
    if (l==r) {
        for (int i=1;i<=n;i++)
         if (a[i][l]==a[i-1][l]) L[now][i]=R[now][i]=L[now][i-1];
         else L[now][i]=R[now][i]=++cnt,sum[now]++;
        return;
    }
    int mid=(l+r)/2;
    build(now<<1,l,mid);
    build(now<<1|1,mid+1,r);
    update(now,l,r);
}
void query(int now,int l,int r,int ll,int rr)
{
    if (ll<=l&&r<=rr) {
        if (!pd) {
            pd=true;
            ans=sum[now];
            for (int i=1;i<=n;i++) ls[i]=L[now][i],rs[i]=R[now][i];
        }
        else {
            ans+=sum[now];
            for (int i=1;i<=n;i++) {
                fa[ls[i]]=ls[i];
                fa[L[now][i]]=L[now][i];
                fa[rs[i]]=rs[i];
                fa[R[now][i]]=R[now][i];
            }   
            for (int i=1;i<=n;i++) 
             if (a[i][l]==a[i][l-1]) {
                int r1=find(L[now][i]); int r2=find(rs[i]);
                if (r1!=r2) {
                    ans--;
                    fa[r2]=r1;
                 }
             }
            for (int i=1;i<=n;i++) {
                ls[i]=find(ls[i]);
                rs[i]=find(R[now][i]);
            }
        }
        return;
    }
    int mid=(l+r)/2;
    if (ll<=mid) query(now<<1,l,mid,ll,rr);
    if (rr>mid) query(now<<1|1,mid+1,r,ll,rr);
}
int main()
{
    freopen("a.in","r",stdin);
    scanf("%d%d%d",&n,&m,&q);
    for (int i=1;i<=n;i++) 
     for (int j=1;j<=m;j++) scanf("%d",&a[i][j]);
    build(1,1,m);
    for (int i=1;i<=q;i++) {
        int l,r; scanf("%d%d",&l,&r);
        pd=false; ans=0;
        query(1,1,m,l,r);
        printf("%d\n",ans);
    }
}

Posted by ankit17_ag on Tue, 12 Feb 2019 21:48:19 -0800