• 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;
    }
    
  • 相关阅读:
    遗传算法中适值函数的标定与大变异算法
    遗传算法中几种不同选择算子及Python实现
    BZOJ_4025_二分图_线段树按时间分治+并查集
    BZOJ_1818_[Cqoi2010]内部白点 _扫描线+树状数组
    BZOJ_3165_[Heoi2013]Segment_线段树
    UOJ_21_【UR #1】缩进优化_数学
    UOJ_14_【UER #1】DZY Loves Graph_并查集
    BZOJ_5359_[Lydsy1805月赛]寻宝游戏_DP
    BZOJ_2813_奇妙的Fibonacci_线性筛
    51nod_1236_序列求和 V3 _组合数学
  • 原文地址:https://www.cnblogs.com/AKMer/p/10218372.html
Copyright © 2020-2023  润新知