2021牛客多校第三场

B :Black and white
非常巧妙的题目,转化成最小生成树,相当于对一个格子(x, y),将它染黑就是对\(x_i, y_j\)连了一条边,要保证图的连通性
还有桶排序的kruskcal

vector<pair<int, int>> v[100001];
int fa[10001];
inline int get(int x) {
    return x == fa[x] ? x : fa[x] = get(fa[x]);
}
void run1() {
    int n = rd(), m = rd(), a = rd(), b = rd(), c = rd(), d = rd(), p = rd(), ans = 0, cnt = 0;
    for(int i = 1; i <= n; ++ i)
    for(int j = 1; j <= m; ++ j) {
        int tmp = ((ll)a * a * b + a * c + d) % p;
        a = tmp;    v[a].push_back({i, n + j});
    }
    for(int i = 1; i <= n + m; ++ i)    fa[i] = i;
    for(int i = 0; i < p; ++ i) {
        for(auto it : v[i]) {
            int f1 = get(it.first), f2 = get(it.second);
            if(f1 != f2)    {
                fa[f1] = f2;
                ans += i;   cnt ++;
                if(cnt == n + m - 1) {
                    printf("%lld\n", ans);
                    return ;
                }
            }
        }
    }
    return ;
}

I:Kuriyama Mirai and Exclusive Or
对于第一个操作、我们使 \(b[i]=a[i]⊕a[i-1]\),\(a[i]\) 即为\(b[i]\)的前缀异或,对区间 l、r 修改 x 即将\(b[l]⊕x\) , \(b[r+1]⊕x\) 即可
对于第二个操作、我们取 \(lowbit(x)\)、即 x 的最后一位1,其为 \(2^K\) ,发现若 \(i-l<2^k\)\(a[i]⊕(x+(i-l))\)可转换为\(a[i]⊕x⊕(i-l)\)
即先将区间 \(l\),\(l+2^k-1\) 异或上x,用第一个操作维护,然后再在这个区间的位置分别异或上\(0、1、2......\)\(2^k-1\),我们令f[i][k]表示
[\(i\),\(i+2^k-1\)]区间
是否需要异或\(0、1、2\)......\(2^k-1\),之后下个区间为[\(l+(1<<k)\),\(r\)],需要异或\(x+(1<<k)+(r-(l+(1<<k)))\)即将 \(x=x+(1<<k)\)\(l=l+(1<<k)\)
正着维护一遍后,有部分区间未被维护且区间小于\(2^k\)满足性质,于是反着再维护一遍
完成所有操作后,我们考虑对f[i][k]维护,若当前遍历到了f[i][k],我们可以将其看作两个区间[\(i\),\(i+2^{k-1}-1\)],[\(i+2^{k-1}\),\(i+2^k-1\)]
对于前一个区间可以直接下放,而对于后一个区间,这一位之后应该异或上\(2^{k-1}\)\(2^{k-1}+1\)......因为满足性质,可以转为区间异或\(2^{k-1}\)用第一个操作维护
然后区间[\(i+2^{k-1}\),\(i+2^k-1\)]依次异或0、1......即下放操作

#include<bits/stdc++.h>
using namespace std;
const int maxn=6e5+10;
int a[maxn];
bool f[maxn][31];
int b[maxn];
int main() {
	int n,m;
	scanf("%d %d",&n,&m);
	for(int i=1; i<=n; i++) {
		scanf("%d",&a[i]);
	}
	for(int i=1; i<=n; i++) {
		b[i]=a[i]^a[i-1];
	}
	for(int i=0; i<m; i++) {
		int op;
		scanf("%d",&op);
		int l,r,x;
		scanf("%d %d %d",&l,&r,&x);
		if(op==0) {
			b[l]^=x;
			b[r+1]^=x;
		} else {
			for(int i=0; i<=30; i++) {
				if(((x>>i)&1)&&(l+(1<<i)-1)<=r) {
					f[l][i]^=1;
					b[l]^=x;
					b[l+(1<<i)]^=x;
					l+=(1<<i);
					x+=(1<<i);
				}
			}
			for(int i=30; i>=0; i--) {
				if((l+(1<<i)-1)<=r) {
					f[l][i]^=1;
					b[l]^=x;
					b[l+(1<<i)]^=x;
					l+=(1<<i);
					x+=(1<<i);
				}
			}
		}
	}
	for(int i=30; i>=1; i--) {
		for(int j=1; j<=n; j++) {
			if(!f[j][i]) continue;
			f[j][i-1]^=1;
			f[j+(1<<(i-1))][i-1]^=1;
			b[j+(1<<(i-1))]^=(1<<(i-1));
			b[j+(1<<i)]^=(1<<(i-1));
		}
	}
	for(int i=1; i<=n; i++)b[i]^=b[i-1];
	for(int i=1; i<=n; i++)printf("%d ",b[i]);
}
posted @ 2021-07-25 19:55  wlhp  阅读(9)  评论(0)    收藏  举报