• BZOJ1453:[WC]Dface双面棋盘


    浅谈树状数组与线段树:https://www.cnblogs.com/AKMer/p/9946944.html

    题目传送门:https://lydsy.com/JudgeOnline/problem.php?id=1453

    线段树维护行区间,每个结点只记录这个区间最上面一行和最下面一行每个格子在当前区间内的并查集情况,然后区间(update)的时候暴力合并就行了。因为除去最上面一行和最下面一行以外的格子都没有用,所以要保证并查集的代表元素是最上面一行或者最下面一行的。

    时间复杂度:(O(mnlogn))

    空间复杂度:(O(n^2))

    代码如下:

    #include <cstdio>
    using namespace std;
    
    int n,m;
    int map[205][205];
    int fa[805],tmp[805];
    
    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*10+ch-'0';
    	return x*f;
    }
    
    int find(int x) {
    	if(fa[x]==x)return x;
    	return fa[x]=find(fa[x]);
    }
    
    struct segment_tree {
    	struct tree_node {
    		int cnt[2],f[405];
    
    		void init(int x) {
    			f[1]=f[n+1]=1;int top=1;
    			cnt[map[x][1]]=1,cnt[map[x][1]^1]=0;
    			for(int i=2;i<=n;i++) {
    				if(map[x][i]!=map[x][top])
    					cnt[map[x][i]]++,top=i;
    				f[i]=f[i+n]=top;
    			}
    		}
    	}tree[805];
    
    	void update(int p,int x) {
    		int ls=p<<1,rs=p<<1|1;
    		for(int i=1;i<=n<<1;i++) {
    			fa[i]=tree[ls].f[i];
    			fa[i+(n<<1)]=tree[rs].f[i]+(n<<1);
    		}
    		tree[p].cnt[0]=tree[ls].cnt[0]+tree[rs].cnt[0];
    		tree[p].cnt[1]=tree[ls].cnt[1]+tree[rs].cnt[1];
    		for(int i=1;i<=n;i++)
    			if(map[x][i]==map[x+1][i]&&find(i+n)!=find(i+(n<<1)))
    				tree[p].cnt[map[x][i]]--,fa[fa[i+n]]=fa[i+(n<<1)];
    		for(int i=1;i<=n<<2;i++) {
    			find(i);
    			if(i<=n)tmp[fa[i]]=i;
    			if(i>n*3)tmp[fa[i]]=i-n*2;
    		}
    		for(int i=1;i<=n;i++) {
    			tree[p].f[i]=tmp[fa[i]];
    			tree[p].f[i+n]=tmp[fa[i+3*n]];
    		}
    	}
    
    	void build(int p,int l,int r) {
    		if(l==r) {tree[p].init(l);return;}
    		int mid=(l+r)>>1;
    		build(p<<1,l,mid);
    		build(p<<1|1,mid+1,r);
    		update(p,mid);
    	}
    
    	void change(int p,int l,int r,int pos) {
    		if(l==r) {tree[p].init(l);return;}
    		int mid=(l+r)>>1;
    		if(pos<=mid)change(p<<1,l,mid,pos);
    		else change(p<<1|1,mid+1,r,pos);
    		update(p,mid);
    	}
    
    	void work() {
    		int x=read(),y=read();
    		map[x][y]^=1;
    		change(1,1,n,x);
    		printf("%d %d
    ",tree[1].cnt[1],tree[1].cnt[0]);
    	}
    }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;
    }
    
  • 相关阅读:
    Pytorch手写线性回归
    numpy+sklearn 手动实现逻辑回归【Python】
    如何用TensorFlow实现线性回归
    进程、线程和携程的通俗解释【刘新宇Python】
    即时通信WebSocket 和Socket.IO
    gRPC【RPC自定义http2.0协议传输】
    Django中MySQL事务的使用
    模拟电磁曲射炮_H题 方案分析【2019年电赛】【刘新宇qq522414928】
    Gitflow工作流
    雪花算法【分布式ID问题】【刘新宇】
  • 原文地址:https://www.cnblogs.com/AKMer/p/10218372.html
Copyright © 2020-2023  润新知