原题传送门

这道题肥肠毒瘤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,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int read()
{
register int x=0,f=1;register char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return x*f;
}
inline void write(register int x)
{
if(!x)putchar('0');if(x<0)x=-x,putchar('-');
static int sta[20];register int tot=0;
while(x)sta[tot++]=x%10,x/=10;
while(tot)putchar(sta[--tot]+48);
}
int n,m;
int a[N][N];
struct node{
int le[N],ri[N],lb[N],rb[N],s0,s1;
}t[N<<2];
int fa[N<<2],tmp[N<<2];
inline int father(register int x)
{
return fa[x]==x?x:fa[x]=father(fa[x]);
}
inline void pushup(register int x)
{
t[x].s0=t[x<<1].s0+t[x<<1|1].s0;
t[x].s1=t[x<<1].s1+t[x<<1|1].s1;
memcpy(t[x].lb,t[x<<1].lb,sizeof(t[x].lb));
memcpy(t[x].rb,t[x<<1|1].rb,sizeof(t[x].rb));
for(register int i=1;i<=n<<2;++i)
fa[i]=i;
for(register int i=1;i<=n;++i)
t[x<<1|1].le[i]+=n<<1,t[x<<1|1].ri[i]+=n<<1;
for(register int i=1;i<=n;++i)
{
int xx=t[x<<1].ri[i],yy=t[x<<1|1].le[i];
if(father(xx)!=father(yy)&&t[x<<1].rb[i]==t[x<<1|1].lb[i])
{
fa[father(xx)]=father(yy);
if(t[x<<1].rb[i])
--t[x].s1;
else
--t[x].s0;
}
}
for(register int i=1;i<=n;++i)
t[x].le[i]=father(t[x<<1].le[i]),t[x].ri[i]=father(t[x<<1|1].ri[i]);
for(register int i=1;i<=n;++i)
tmp[i<<1]=t[x].le[i],tmp[(i<<1)-1]=t[x].ri[i];
sort(tmp+1,tmp+1+(n<<1));
int maxsum=unique(tmp+1,tmp+1+(n<<1))-tmp-1;
for(register int i=1;i<=n;++i)
{
t[x].le[i]=lower_bound(tmp+1,tmp+1+maxsum,t[x].le[i])-tmp;
t[x].ri[i]=lower_bound(tmp+1,tmp+1+maxsum,t[x].ri[i])-tmp;
}
for(register int i=1;i<=n;++i)
t[x<<1|1].le[i]-=n<<1,t[x<<1|1].ri[i]-=n<<1;
}
inline void build(register int x,register int l,register int r)
{
if(l==r)
{
int tot=0;
for(register int i=1;i<=n;++i)
{
if(a[i][l]!=a[i-1][l])
{
++tot;
if(a[i][l])
++t[x].s1;
else
++t[x].s0;
}
t[x].le[i]=t[x].ri[i]=tot;
t[x].lb[i]=t[x].rb[i]=a[i][l];
}
return;
}
int mid=l+r>>1;
build(x<<1,l,mid);
build(x<<1|1,mid+1,r);
pushup(x);
}
inline void change(register int x,register int l,register int r,register int pos)
{
if(l==r)
{
int tot=0;
t[x].s0=t[x].s1=0;
for(register int i=1;i<=n;++i)
{
if(a[i][l]!=a[i-1][l])
{
++tot;
if(a[i][l])
++t[x].s1;
else
++t[x].s0;
}
t[x].le[i]=t[x].ri[i]=tot;
t[x].lb[i]=t[x].rb[i]=a[i][l];
}
return;
}
int mid=l+r>>1;
if(pos<=mid)
change(x<<1,l,mid,pos);
else
change(x<<1|1,mid+1,r,pos);
pushup(x);
}
int main()
{
n=read();
for(register int i=1;i<=n;++i)
{
a[0][i]=-1;
for(register int j=1;j<=n;++j)
a[i][j]=read();
}
build(1,1,n);
m=read();
while(m--)
{
int x=read(),y=read();
a[x][y]^=1;
change(1,1,n,y);
write(t[1].s1),putchar(' '),write(t[1].s0),puts("");
}
return 0;
}

好像珂以用lct维护连通性?

不用强制在线,我们珂以离线处理

计算每条边加入和删除的时间,就珂以用lct维护删除时间最靠后的生成树

代码(抄来的)

#include <bits/stdc++.h>
#define C 205
#define N 200005
#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,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int read()
{
register int x=0,f=1;register char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return x*f;
}
inline void write(register int x)
{
if(!x)putchar('0');if(x<0)x=-x,putchar('-');
static int sta[20];register int tot=0;
while(x)sta[tot++]=x%10,x/=10;
while(tot)putchar(sta[--tot]+48);
}
int dx[4]={0,0,1,-1};
int dy[4]={1,-1,0,0};
int n,m,sz;
int color[C][C],c[C][C],ans[2];
struct data{
int x,y,t,d,id,opt,c;
bool operator < (const data &a) const
{
return x<a.x||x==a.x&&y<a.y;
}
}e[N],opr[10005];
inline bool cmp(register data a,register data b)
{
return a.t<b.t||(a.t==b.t&&a.opt<b.opt);
}
map <data,int> mp;
int cnt=0;
inline int eid(register int a,register int b,register int c,register int d)
{
if(a==c)
{
if(b>d)
b^=d^=b^=d;
return (a-1)*(n-1)+b;
}
else
{
if(a>c)
a^=c^=a^=c;
return n*(n-1)+(a-1)*n+b;
}
}
int f[N],ch[N][2],minn[N],rev[N],sta[N],val[N];
int re[N],pt[N],l[N],r[N],tree[N];
inline bool isroot(register int x)
{
return ch[f[x]][0]!=x&&ch[f[x]][1]!=x;
}
inline int get(register int x)
{
return ch[f[x]][1]==x;
}
inline void update(register int x)
{
int loc=x;
if(ch[x][0])
{
if(val[minn[ch[x][0]]]<val[loc])
loc=minn[ch[x][0]];
}
if(ch[x][1])
{
if(val[minn[ch[x][1]]]<val[loc])
loc=minn[ch[x][1]];
}
minn[x]=loc;
}
inline void pushdown(register int x)
{
if(x&&rev[x])
{
if(ch[x][0])
rev[ch[x][0]]^=1;
if(ch[x][1])
rev[ch[x][1]]^=1;
ch[x][0]^=ch[x][1]^=ch[x][0]^=ch[x][1];
rev[x]=0;
}
}
inline void rotate(register int x)
{
int old=f[x],oldf=f[old],wh=get(x);
if(!isroot(old))
ch[oldf][ch[oldf][1]==old]=x;
f[x]=oldf;
ch[old][wh]=ch[x][wh^1];
if(ch[old][wh])
f[ch[old][wh]]=old;
ch[x][wh^1]=old;
f[old]=x;
update(old);
update(x);
}
inline void splay(register int x)
{
int top=0;
sta[++top]=x;
for(register int i=x;!isroot(i);i=f[i])
sta[++top]=f[i];
for(register int i=top;i;--i)
pushdown(sta[i]);
for(register int fa;!isroot(x);rotate(x))
if (!isroot(fa=f[x]))
rotate((get(x)==get(fa))?fa:x);
}
inline void access(register int x)
{
int t=0;
for(;x;t=x,x=f[x])
{
splay(x);
ch[x][1]=t;
update(x);
}
}
inline void reverse(register int x)
{
access(x);
splay(x);
rev[x]^=1;
}
inline int find(register int x)
{
access(x);
splay(x);
while(ch[x][0])
x=ch[x][0];
return x;
}
inline void link(register int x,register int y)
{
reverse(x);
f[x]=y;
}
inline void cut(register int x,register int y)
{
reverse(x);
access(y);
splay(y);
ch[y][0]=f[x]=0;
}
inline void add(register int i,register int cc)
{
int x=e[i].x,y=e[i].y,d=e[i].d,id=e[i].id;
if(find(x)==find(y))
{
reverse(x);
access(y);
splay(y);
int loc=minn[y];
if(d<=val[loc])
return;
cut(loc,l[loc]);
cut(loc,r[loc]);
tree[re[loc]]=0;
}
else
--ans[cc];
++sz;
val[sz]=d,re[sz]=id,pt[id]=sz,tree[id]=1;
l[sz]=x,r[sz]=y;
link(x,sz);
link(y,sz);
}
inline void del(register int i)
{
int x=e[i].x,y=e[i].y,id=e[i].id;
cut(x,pt[id]);
cut(y,pt[id]);
tree[id]=0;
}
int main()
{
n=read();
for(register int i=1;i<=n;++i)
for(register int j=1;j<=n;++j)
{
color[i][j]=c[i][j]=read();
++ans[c[i][j]];
}
for(register int i=1;i<=n;++i)
for(register int j=1;j<=n;++j)
{
int num=(i-1)*n+j,cc=color[i][j];
if(j!=n&&color[i][j+1]==cc)
e[++cnt].x=num,e[cnt].y=num+1,e[cnt].t=0,e[cnt].id=eid(i,j,i,j+1),e[cnt].opt=1,e[cnt].c=cc;
if(i!=n&&color[i+1][j]==cc)
e[++cnt].x=num,e[cnt].y=num+n,e[cnt].t=0,e[cnt].id=eid(i,j,i+1,j),e[cnt].opt=1,e[cnt].c=cc;
}
m=read();
for(register int i=1;i<=m;++i)
{
int x=read(),y=read();
opr[i].x=x,opr[i].y=y;
int num=(x-1)*n+y;
for(register int j=0;j<4;++j)
{
int nx=x+dx[j],ny=y+dy[j],nnum=(nx-1)*n+ny;
if(nx<=0||ny<=0||nx>n||ny>n)
continue;
if(c[x][y]==c[nx][ny])
e[++cnt].x=num,e[cnt].y=nnum,e[cnt].t=i,e[cnt].id=eid(x,y,nx,ny),e[cnt].opt=-1;
else
e[++cnt].x=num,e[cnt].y=nnum,e[cnt].t=i,e[cnt].id=eid(x,y,nx,ny),e[cnt].opt=1;
}
c[x][y]^=1;
}
sort(e+1,e+cnt+1,cmp);
for(register int i=1;i<=cnt;++i)
e[i].d=m+1;
mp.clear();
for(register int i=cnt;i>=1;--i)
{
if(e[i].x>e[i].y)
e[i].x^=e[i].y^=e[i].x^=e[i].y;
if(mp[e[i]])
e[i].d=mp[e[i]];
mp[e[i]]=e[i].t;
}
sz=n*n;
memset(val,127,sizeof(val));
int now=1;
for(;now<=cnt&&e[now].t<=0;++now)
add(now,e[now].c);
for(register int i=1;i<=m;++i)
{
int x=opr[i].x,y=opr[i].y;
int cc=color[x][y];
for(;now<=cnt&&e[now].t<=i;++now)
if(e[now].opt==-1)
{
if(!tree[e[now].id])
continue;
del(now);
++ans[cc];
}
else
add(now,cc^1);
--ans[cc],++ans[cc^1];
color[x][y]^=1;
write(ans[1]),putchar(' '),write(ans[0]),puts("");
}
return 0;
}

【题解】Luogu P4121 [WC2005]双面棋盘的更多相关文章

  1. P4121 [WC2005]双面棋盘

    题目 P4121 [WC2005]双面棋盘 貌似是刘汝佳出的题目?? 做法 线段树维护并查集 线段树分治\(1\)~\(n\)行,我们要考虑维护的肯定是黑.白各自的联通块数量 考虑区间合并,其实就与中 ...

  2. 洛谷P4121 [WC2005]双面棋盘(线段树套并查集)

    传送门 先膜一下大佬->这里 据说这题正解是LCT,然而感觉还是线段树套并查集的更容易理解 我们对于行与行之间用线段树维护,每一行内用并查集暴力枚举 每一行内用并查集暴力枚举连通块这个应该容易理 ...

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

    题目描述 题解 唉,还是码力不行,写了一个多小时发现想错了又重构了一个多小时. 这道题意图很显然,动态维护联通块,有一个经典做法就是用LCT维护按照删除时间维护的最大生成树. 网上还有一种神奇的做法, ...

  4. [WC2005]双面棋盘

    description 洛谷 给出一个\(n\times n\)的黑白棋盘. \(m\)次操作,每次将一个格子进行颜色翻转,求每次操作后的黑白四连通块数. data range \[n\le 200, ...

  5. [WC2005]双面棋盘(线段树+并查集)

    线段树+并查集维护连通性. 好像 \(700ms\) 的时限把我的常数超级大的做法卡掉了, 必须要开 \(O_2\) 才行. 对于线段树的每一个结点都开左边的并查集,右边的并查集,然后合并. \(Co ...

  6. 【BZOJ1453】[Wc]Dface双面棋盘 线段树+并查集

    [BZOJ1453][Wc]Dface双面棋盘 Description Input Output Sample Input Sample Output HINT 题解:话说看到题的第一反应其实是LCT ...

  7. bzoj 1453: [Wc]Dface双面棋盘

    1453: [Wc]Dface双面棋盘 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 617  Solved: 317[Submit][Status][ ...

  8. [题解] Luogu P5446 [THUPC2018]绿绿和串串

    [题解] Luogu P5446 [THUPC2018]绿绿和串串 ·题目大意 定义一个翻转操作\(f(S_n)\),表示对于一个字符串\(S_n\), 有\(f(S)= \{S_1,S_2,..., ...

  9. BZOJ1453: [WC2005]Dface双面棋盘

    离线LCT维护MST,和3082的方法一样.然而比较码农,适合颓废的时候写. PS:线段树分治要好写得多,LCT比较自娱自乐. #include<bits/stdc++.h> using ...

随机推荐

  1. esyui datagrid 水平方向下方出来滚动条的原因是因为使用了同一列名

    esyui datagrid 水平方向下方出来滚动条的原因是因为使用了同一列名

  2. Server response error code:404, error:{"ret":-1, "msg":"invalid appkey"}

    Server response error code:404, error:{"ret":-1, "msg":"invalid appkey" ...

  3. js滚动条滚动到底部触发事件

    $("#contain").scroll(function(){ var $this =$(this), viewH =$(this).height(),//可见高度 conten ...

  4. Spark开发wordcount程序

    1.java版本(spark-2.1.0) package chavin.king; import org.apache.spark.api.java.JavaSparkContext; import ...

  5. Kafka: Exactly-once Semantics

    https://www.confluent.io/blog/enabling-exactly-kafka-streams/ https://cwiki.apache.org/confluence/di ...

  6. Android平台targetSdkVersion设置及动态权限

    --关于Android动态权限和targetSdkVersion Android系统自6.0开始,提供动态权限机制,对于敏感权限(存储,定位,录音,拍照,录像等),需要在APP运行过程中动态向用户申请 ...

  7. 2017(2)数据库设计,数据库设计过程,ER模型,规范化理论

    试题二(共 25 分〉 阅读以下关于系统数据分析与建模的叙述,在答题纸上回答问题1 至问题 3. [说明] 某软件公司受快递公司委托,拟开发一套快递业务综合管理系统,实现快递单和物流信息的综合管理.项 ...

  8. 读书笔记一【哈希——MD5】

    计算机中,将某种数据转换成指定范围内的数字数字或字母叫做哈希(散列.hashing) 哈希后的值无法像加密解密那样恢复为原文值,通常用于文件校验或数字签名等 好的散列算法应具有: 充分利用所有数据位 ...

  9. selenium--鼠标事件

    鼠标事件perform() #执行所有ActionChains中存储的行为context_click() #右击事件double_click() #双击事件drag_and_drop(source,t ...

  10. OO第二单元电梯线程系列总结作业

    电梯系列第一次作业 功能描述: 傻瓜电梯无需考虑超载捎带 线程模式: Producer-Consumer Pattern 思路: 第一次作业是一个傻瓜电梯,分别有一个生产者生成电梯指令(也就是Inpu ...