[Wc]Dface双面棋盘

Description

Input

Output

Sample Input

Sample Output

HINT

线段树+并查集,暴力记录和更新一些信息,详情见代码注解。

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define inf 0x7f7f7f7f
using namespace std;
typedef long long ll;
typedef unsigned int ui;
typedef unsigned long long ull;
inline int read(){
    int x=0,f=1;char ch=getchar();
    for (;ch<‘0‘||ch>‘9‘;ch=getchar())  if (ch==‘-‘)    f=-1;
    for (;ch>=‘0‘&&ch<=‘9‘;ch=getchar())    x=(x<<1)+(x<<3)+ch-‘0‘;
    return x*f;
}
inline void print(int x){
    if (x>=10)     print(x/10);
    putchar(x%10+‘0‘);
}
const int N=2e2;
int map[N+10][N+10];
int ID[N*4+10],fa[N*4+10];
int n,m;
int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
struct Segment{
    #define ls (p<<1)
    #define rs (p<<1|1)
    struct AC{//线段树记录列数,struct内存储一个列区间的信息
        int lcnt[N+10],rcnt[N+10];  //记录最左列和最右列每行的联通块个数,相当于编号
        int W,B,T;  //记录白块(W),黑块(B)个数,T为lcnt[n]+rcnt[n]
        int l,r;
        void clear(){
            l=r=W=B=T=0;
            memset(lcnt,0,sizeof(lcnt));
            memset(rcnt,0,sizeof(rcnt));
        }
        void init(int x){//单点暴力
            B=W=0;
            for (int i=1;i<=n;i++){
                if (i==1||map[i][x]!=map[i-1][x])   map[i][x]?B++:W++;
                lcnt[i]=rcnt[i]=B+W;
            }
            T=B+W;
        }
    }tree[N*4+10];
    friend AC operator +(const AC &x,const AC &y){
        AC z; z.clear();
        z.l=x.l,z.r=y.r;
        z.B=x.B+y.B;
        z.W=x.W+y.W;
        for (int i=1;i<=x.T+y.T;i++)    fa[i]=i,ID[i]=0;    //T的用处(优化)
        for (int i=1,p1,p2;i<=n;i++){//把y的信息加上x.T,使它们为一个图
            if (map[i][x.r]!=map[i][y.l])   continue;
            if ((p1=find(x.rcnt[i]))!=(p2=find(y.lcnt[i]+x.T))){
                fa[p2]=p1;  //记得连向小的标号……
                map[i][x.r]?z.B--:z.W--;
            }
        }
        int Rank=0;
        for (int i=1;i<=n;i++){//离散化
            int p1=find(x.lcnt[i]),p2=find(y.rcnt[i]+x.T);
            if (!ID[p1])    ID[p1]=++Rank;
            if (!ID[p2])    ID[p2]=++Rank;
            z.lcnt[i]=ID[p1];
            z.rcnt[i]=ID[p2];
        }
        z.T=Rank;
        return z;
    }
    void build(int p,int l,int r){
        tree[p].l=l,tree[p].r=r;
        if (l==r){
            tree[p].init(l);
            return;
        }
        int mid=(l+r)>>1;
        build(ls,l,mid),build(rs,mid+1,r);
        tree[p]=tree[ls]+tree[rs];
    }
    void change(int p,int l,int r,int x){
        if (l==r){
            tree[p].init(l);
            return;
        }
        int mid=(l+r)>>1;
        if (x<=mid) change(ls,l,mid,x);
        if (x>mid)  change(rs,mid+1,r,x);
        tree[p]=tree[ls]+tree[rs];
    }
    void work(){
        int x=read(),y=read();
        map[x][y]^=1;
        change(1,1,n,y);
        printf("%d %d\n",tree[1].B,tree[1].W);
    }
}T;
int main(){
    n=read();
    for (int i=1;i<=n;i++)  for (int j=1;j<=n;j++)  map[i][j]=read();
    T.build(1,1,n);
    m=read();
    for (int i=1;i<=m;i++)  T.work();
    return 0;
}

原文地址:https://www.cnblogs.com/Wolfycz/p/8414611.html

时间: 2024-10-15 09:49:27

[Wc]Dface双面棋盘的相关文章

bzoj 1453: [Wc]Dface双面棋盘

1453: [Wc]Dface双面棋盘 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 617  Solved: 317[Submit][Status][Discuss] Description Input Output Sample Input Sample Output HINT 用线段树+数组模拟并查集,维护每一列的连通性,然后暴力合并就行了,常数巨大 #include<cstdio> #include<cstring> #inc

bzoj1453: [Wc]Dface双面棋盘

Description Input Output 经典的按时间分治维护图的动态连通性 #include<cstdio> #include<vector> int n,m,ans[2]; int v[207][207],id[207][207],idp=0,t1[207][207],t2[207][207]; int f[40007],h[40007],aa[40007][2]; int*op1[1000007],op2[1000007],opp=0; inline void set

1453: [Wc]Dface双面棋盘 (线段树+并茶几)

Description Input Output Sample Input Sample Output HINT 1 /* 2 线段树+并查集维护 3 线段树维护每列的信息 4 le 代表区间左端一列连通性的信息 5 ri 代表区间右端一列连通性的信息 6 w,b 分别代表白色连通块和黑色连通块的个数 7 lb 代表区间左端一列黑白点的信息 8 rb 代表区间右端一列黑白点的信息 9 tmp用来暂时存储连通块个数 10 */ 11 #include<cstdio> 12 #include<

bzoj 1453 双面棋盘

题目大意: 一个黑白方格图 支持单点修改 查询黑色与白色联通快个数 思路: 可以把每一行压为一个点 使用线段树来维护 然后两行合并的时候使用并查集来合并 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<cmath> 6 #include<algorithm> 7 #include<queue>

[WC2005]双面棋盘(并查集+分治)

题目描述 题解 唉,还是码力不行,写了一个多小时发现想错了又重构了一个多小时. 这道题意图很显然,动态维护联通块,有一个经典做法就是用LCT维护按照删除时间维护的最大生成树. 网上还有一种神奇的做法,线段树套并查集,蒟蒻表示不懂.. 这道题可以利用并查集操作可以撤销这种性质来做. 线段树分治 线段树分治可以分两种情况,操作之间独立和操作之间不独立. 操作之间独立意味着我先完成哪个操作就可以,例如找最优点,有一道例题. 还有一种是操作之间是可以相互影响的,比如说这道题,连通性这种东西和我加的每一条

【题解】Luogu P4121 [WC2005]双面棋盘

原题传送门 这道题肥肠毒瘤qwqwq,我被卡了qwqwq 这题的正解好像是线段树+并查集,但由于我人丑常数大被卡成了70 #include <bits/stdc++.h> #define N 205 #define getchar nc using namespace std; inline char nc(){ static char buf[100000],*p1=buf,*p2=buf; return p1==p2&&(p2=(p1=buf)+fread(buf,1,10

线段树分治总结(线段树分治,线段树,并查集,树的dfn序,二分图染色)

闲话 stO猫锟学长,满脑子神仙DS 线段树分治思想 我们在做CDQ的时候,将询问和操作通通视为元素,在归并过程中统计左边的操作对右边的询问的贡献. 而在线段树分治中,询问被固定了.按时间轴确定好询问的序列以后,我们还需要所有的操作都会影响一个时间区间.而这个区间,毫无疑问正好对应着询问的一段区间. 于是,我们可以将每一个操作丢到若干询问里做区间修改了,而线段树可以高效地维护.我们开一个叶子节点下标为询问排列的线段树,作为分治过程的底层结构. 具体的实现,仍然要看题目. 例题1 BZOJ4025

wc.exe命令行程序——c语言实现

1 /* 2 * 没能实现的功能:wc.exe -s递归处理目录下符合条件的文件 3 * wc.exe -x 显示图形界面 4 * 5 * 6 * 实现的功能: wc.exe -c显示文件的字符数. 7 * wc.exe -l行数. 8 * wc.exe -w单词. 9 * wc.exe -a空行数.代码行数.注释行数的统计测试 10 *` 11 * 12 */ 13 14 #include"iostream" 15 using namespace std; 16 void CharC

linux中wc命令用法

Linux系统中的wc(Word Count)命令的功能为统计指定文件中的字节数.字数.行数,并将统计结果显示输出. 1.命令格式: wc [选项]文件... 2.命令功能: 统计指定文件中的字节数.字数.行数,并将统计结果显示输出.该命令统计指定文件中的字节数.字数.行数.如果没有给出文件名,则从标准输入读取.wc同时也给出所指定文件的总统计数. 3.命令参数: -c 统计字节数. -l 统计行数. -m 统计字符数.这个标志不能与 -c 标志一起使用. -w 统计字数.一个字被定义为由空白.