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<cstring>
 13 #include<iostream>
 14 #include<algorithm>
 15 #define MAXN 210
 16
 17 using namespace std;
 18
 19 struct node {
 20     int l,r;
 21     int w,b;
 22     int le[MAXN],ri[MAXN];
 23     int lb[MAXN],rb[MAXN];
 24 };
 25 node t[MAXN<<2];
 26
 27 int a[MAXN][MAXN],n,m;
 28
 29 int fa[MAXN<<2],tmp[MAXN<<2];
 30
 31 inline void read(int&x) {
 32     int f=1;x=0;char c=getchar();
 33     while(c>‘9‘||c<‘0‘) {if(c==‘-‘) f=-1;c=getchar();}
 34     while(c>=‘0‘&&c<=‘9‘) {x=(x<<1)+(x<<3)+c-48;c=getchar();}
 35     x=x*f;
 36 }
 37
 38 inline int find(int x) {
 39     if(x==fa[x]) return fa[x];
 40     else return fa[x]=find(fa[x]);
 41 }
 42
 43 inline void up(int now) {
 44     t[now].w=t[now<<1].w+t[now*2+1].w;
 45     t[now].b=t[now<<1].b+t[now*2+1].b;
 46     memcpy(t[now].lb,t[now<<1].lb,sizeof t[now].lb);
 47     memcpy(t[now].rb,t[now*2+1].rb,sizeof t[now].rb);
 48     for(int i=1;i<=3*n;i++) fa[i]=i;
 49     for(int i=1;i<=n;i++)
 50       t[now*2+1].le[i]+=2*n,t[now*2+1].ri[i]+=2*n;
 51     for(int i=1;i<=n;i++) {
 52         int x=t[now<<1].ri[i],y=t[now*2+1].le[i];
 53             if(find(x)!=find(y)&&t[now<<1].rb[i]==t[now*2+1].lb[i]) {
 54             fa[find(x)]=find(y);
 55             if(t[now<<1].rb[i]) t[now].b--;
 56             else t[now].w--;
 57         }
 58     }
 59     for(int i=1;i<=n;i++)
 60       t[now].le[i]=find(t[now<<1].le[i]),t[now].ri[i]=find(t[now*2+1].ri[i]);
 61     for(int i=1;i<=n;i++)
 62       tmp[i<<1]=t[now].le[i],tmp[(i<<1)-1]=t[now].ri[i];
 63     sort(tmp+1,tmp+1+2*n);
 64     int maxdata=unique(tmp+1,tmp+1+2*n)-tmp-1;
 65     for(int i=1;i<=n;i++)
 66       t[now].le[i]=lower_bound(tmp+1,tmp+1+maxdata,t[now].le[i])-tmp,t[now].ri[i]=lower_bound(tmp+1,tmp+1+maxdata,t[now].ri[i])-tmp;
 67     for(int i=1;i<=n;i++) t[now*2+1].le[i]-=2*n,t[now*2+1].ri[i]-=2*n;
 68     return;
 69 }
 70
 71 void build_tree(int now,int l,int r) {
 72     t[now].l=l;
 73     t[now].r=r;
 74     if(l==r) {
 75         int tot=0;
 76         for(int i=1;i<=n;i++) {
 77             if(a[i][l]!=a[i-1][l]) {
 78                 tot++;
 79                 if(a[i][l]) t[now].b++;
 80                 else t[now].w++;
 81             }
 82             t[now].le[i]=t[now].ri[i]=tot;
 83             t[now].lb[i]=t[now].rb[i]=a[i][l];
 84         }
 85         return;
 86     }
 87     int mid=(l+r)>>1;
 88     build_tree(now<<1,l,mid);
 89     build_tree(now*2+1,mid+1,r);
 90     up(now);
 91 }
 92
 93 void modify(int now,int pos) {
 94     if(t[now].l==t[now].r) {
 95         int tot=0;
 96         t[now].b=0;
 97         t[now].w=0;
 98         for(int i=1;i<=n;i++) {
 99             if(a[i][pos]!=a[i-1][pos]) {
100                 tot++;
101                 if(a[i][pos]) t[now].b++;
102                 else t[now].w++;
103             }
104             t[now].le[i]=t[now].ri[i]=tot;
105             t[now].lb[i]=t[now].rb[i]=a[i][pos];
106         }
107         return;
108     }
109     int mid=(t[now].l+t[now].r)>>1;
110     if(pos<=mid) modify(now<<1,pos);
111     else modify(now*2+1,pos);
112     up(now);
113 }
114
115 int main() {
116     read(n);
117     for(int i=1;i<=n;i++) {
118         a[0][i]=-1;
119         for(int j=1;j<=n;j++)
120           read(a[i][j]);
121     }
122     build_tree(1,1,n);
123     read(m);
124     for(int i=1;i<=m;i++) {
125         int x,y;
126         read(x);read(y);
127         a[x][y]^=1;
128         modify(1,y);
129         printf("%d %d\n",t[1].b,t[1].w);
130     }
131     return 0;
132 }

题解

时间: 2024-08-13 12:00:49

1453: [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

[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; typed

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

CSU 1453: 平衡序列 学会线段树后必做

http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1453. 题目:给定一个大小为100000的数组,里面的数字最大也是100000.现在叫你求出一段子序列,使得他们任意两个数差的绝对值都不能超过k 其实这题的关键是数字的范围,不超过100000,这样的话 ,就可以用线段树整段覆盖了.记dp[i]为以这个数字为结尾的,最长的LIS的多少,开始的时候dp[i]=0,用线段树把他覆盖了.每次插入一个数a[i]的时候,都去找[a[i]-k,a[i]+k]

BZOJ 2877 NOI2012 魔幻棋盘 二维线段树

题目大意:给定一个矩阵,支持两种操作: 1.将某个子矩阵中的每个值增加一个数 2.询问某个子矩阵中的所有数的GCD 已知所有询问恒过定点(x,y) 算了BZOJ没有原题我还是把原题发上来吧- - <论代码长度与注释长度以及题目简单程度的比例失调关系以及日本饮用水资源的解决方案> <10K+代码是怎样炼成的> <GCD与修改标记的正确用法> <出题人我*你吗系列> <懒惰即美德> 咳咳. 首先我们可以维护一个二维线段树支持子矩阵修改和子矩阵查询 但

bzoj 1453 双面棋盘

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

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

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

hdu 5480 Conturbatio 线段树 单点更新,区间查询最小值

Conturbatio Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=5480 Description There are many rook on a chessboard, a rook can attack the row and column it belongs, including its own place. There are also many quer

树状数组与线段树

一:树状数组 树状数组是对一个数组改变某个元素和求和比较实用的数据结构.两中操作都是O(logn). 需求:有时候我们需要频繁地求数组的前k项和或者求数组从小标i到j的和,这样每次最坏情况下的时间复杂度就会为O(N),这样效率太低了.而树状数组主要就是为了解决这样一个问题.树状数组在求和及修改都可以在O(lgN)时间内完成. 树状数组需要额外维护一个数组,我们设为C[N],原数组为A[N], 其中每个元素C[i]表示A[i-2^k+1]到A[i]的和,这里k是i在二进制时末尾0的个数.注意通过位