CF811E(线段树+并查集)

http://codeforces.com/problemset/problem/811/E
cf的题面真的是做的美美的,
所以就直接扔超链接了

分析:
线段树的叶子结点维护一列的信息
包括左右端点,有多少联通块,以及左右两列的并查集情况
需要注意的是,
这次代码中的update返回的是一个node
第一次代码re的原因就是在返回的这个新建的node中
我没有维护左右端点

tip

在update维护左右两列的并查集时,
这里写图片描述

这里写图片描述
(160个点,怀疑人生。。。)

这里写代码片
#include<cstdio>
#include<cstring>
#include<iostream>

using namespace std;

const int N=1e5+7;
struct node{
    int x,y,l[11],r[11],sum;
};
node tree[N<<2];
int n,m,q,mp[11][N];
int fa[N*11],tot=0;

int find(int a)
{
    if (fa[a]!=a) fa[a]=find(fa[a]);
    return fa[a];
}

node update(int ll,int rr,node lc,node rc,int mid)
{
    int i;
    node ans;
    ans.x=ll;
    ans.y=rr;
    ans.sum=lc.sum+rc.sum;
    for (i=1;i<=n;i++)
    {
        fa[lc.l[i]]=lc.l[i];
        fa[lc.r[i]]=lc.r[i];
        fa[rc.l[i]]=rc.l[i];
        fa[rc.r[i]]=rc.r[i];
    }
    for (i=1;i<=n;i++)
    {
        if (mp[i][mid]==mp[i][mid+1])
        {
            int f1=find(lc.r[i]);
            int f2=find(rc.l[i]);
            if (f1!=f2)
            {
                fa[f1]=f2;
                ans.sum--;
            }
        }
    }
    for (i=1;i<=n;i++)
    {
        ans.l[i]=find(lc.l[i]);  ///
        ans.r[i]=find(rc.r[i]);  ///
    }
    return ans;
}

void build(int bh,int ll,int rr)
{
    tree[bh].x=ll;
    tree[bh].y=rr;
    if (ll==rr)
    {
        tree[bh].sum=n;
        for (int i=1;i<=n;i++)
        {
            if (mp[i][ll]==mp[i-1][ll])
               tree[bh].l[i]=tree[bh].r[i]=tree[bh].l[i-1],tree[bh].sum--;
            else                                                                 
               tree[bh].l[i]=tree[bh].r[i]=++tot;
        }
        return;
    }
    int mid=(ll+rr)>>1;
    build(bh<<1,ll,mid);
    build(bh<<1|1,mid+1,rr);
    tree[bh]=update(tree[bh].x,tree[bh].y,tree[bh<<1],tree[bh<<1|1],mid);
}

node ask(int bh,int ll,int rr)
{
    if (tree[bh].x>=ll&&tree[bh].y<=rr)
    {
        return tree[bh];
    }
    int mid=(tree[bh].x+tree[bh].y)>>1;
    if (rr<=mid) return ask(bh<<1,ll,rr);
    else if (ll>mid) return ask(bh<<1|1,ll,rr);
    else
    {
        return update(ll,rr,ask(bh<<1,ll,rr),ask(bh<<1|1,ll,rr),mid);
    }
}

int main()
{
    scanf("%d%d%d",&n,&m,&q);
    for (int i=1;i<=n;i++)
        for (int j=1;j<=m;j++)
            scanf("%d",&mp[i][j]);
    tot=0;
    build(1,1,m);
    while (q--)
    {
        int u,w;
        scanf("%d%d",&u,&w);
        node ans=ask(1,u,w);
        printf("%d
",ans.sum);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/wutongtong3117/p/7673420.html