Codeforces

来源:互联网 发布:淘宝如何免费推广 编辑:程序博客网 时间:2024/06/10 14:32

题目连接:Codeforces - 811E - Vladik and Entertaining Flags

线段树结点[L,R]维护区间 [L,R] 的答案和第 L 列与第 R 列中所有结点的连通关系。
两个相邻区间 [L1,R1][L2,R2] 合并时,第 R1 列与第 L2 列相邻的结点颜色相同的用并查集连接起来,同时答案-1就行。然后更新新结点的连通关系。
这样相当于线段树维护区间答案和区间并查集。

合并的复杂度是 O(n) ,因此总的复杂度为 O(nmlogm+nqlogm)

#include<bits/stdc++.h>using namespace std;const int N=1e5+7;struct Node{    int l,r,ans,u[11],d[11];}tr[N<<2];int n,m,q,G[11][N];int fa[41],vis[41];int f(int x){return x==fa[x]?x:fa[x]=f(fa[x]); }inline void Union(int x,int y){    x=f(x);y=f(y);    fa[x]=y;}Node merge(const Node& a,const Node& b){    Node res;    res.l=a.l;    res.r=b.r;    res.ans=a.ans+b.ans;    for(int i=1;i<=n;i++) fa[i]=a.u[i];    for(int i=1;i<=n;i++) fa[i+n]=a.d[i];    for(int i=1;i<=n;i++) fa[i+n*2]=b.u[i]+n*2;    for(int i=1;i<=n;i++) fa[i+n*3]=b.d[i]+n*2;    for(int i=1;i<=n;i++)        if(G[i][a.r]==G[i][b.l]&&f(i+n)!=f(i+n*2)) Union(i+n,i+2*n),--res.ans;    memset(vis,0,sizeof(vis));    for(int i=1;i<=n;i++)    {        if(!vis[f(i)]) res.u[i]=i,vis[f(i)]=i;        else res.u[i]=vis[f(i)];        if(!vis[f(i+3*n)]) res.d[i]=i+n,vis[f(i+3*n)]=i+n;        else res.d[i]=vis[f(i+3*n)];    }    return res;}void build(int rt,int l,int r){    if(l==r)    {        Node &t=tr[rt];        t.l=t.r=l;        t.u[1]=t.d[1]=t.ans=1;        for(int i=2;i<=n;i++)            if(G[i][l]!=G[i-1][l])                t.u[i]=t.d[i]=i,++t.ans;            else t.u[i]=t.d[i]=t.u[i-1];        return ;    }    int mid=(l+r)>>1;    build(rt<<1,l,mid);    build(rt<<1|1,mid+1,r);    tr[rt]=merge(tr[rt<<1],tr[rt<<1|1]);    //printf("%d\n",tr[rt].ans);}Node query(int rt, int l, int r, int ql, int qr){    if(l>=ql&&r<=qr)        return tr[rt];    int mid=(l+r)>>1;    if(ql>mid) return query(rt<<1|1,mid+1,r,ql,qr);    else if(qr<=mid) return query(rt<<1,l,mid,ql,qr);    else return merge(query(rt<<1,l,mid,ql,qr),query(rt<<1|1,mid+1,r,ql,qr));}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",&G[i][j]);    int l,r;    build(1,1,m);    while(q--)    {        scanf("%d%d",&l,&r);        printf("%d\n",query(1,1,m,l,r).ans);    }    return 0;}
原创粉丝点击