zoukankan      html  css  js  c++  java
  • CF 811E Vladik and Entertaining Flags

    link

    题解

    考虑求连通块个数可以用并查集,区间询问可以用线段树。把他们丢在一起做即可。
    具体地,线段树每个结点维护对应区间的连通块个数、对应区间最左边的一列、对应区间最右边的一列。
    线段树合并信息的时候就是对相邻两列用并查集合并。
    如果并查集能合并,那么连通块个数减一。

    #include <cstdio>
    #include <cctype>
    #include <cstring>
    #define MAX_N (10 + 5)
    #define MAX_M (100000 + 5)
    int n, m, q;
    int a[MAX_N][MAX_M];
    int rt[MAX_N * MAX_M], tot;
    struct Node {
    	int cnt, l[MAX_N], r[MAX_N];
    } s[MAX_M << 2], ans;
    void Read(int &x) {
    	x = 0;
    	char ch = getchar();
    	while (!isdigit(ch)) ch = getchar();
    	while (isdigit(ch)) x = x * 10 + ch - '0', ch = getchar();
    }
    void Write(int x) {
    	if (x >= 10) Write(x / 10);
    	putchar(x % 10 + '0');
    }
    int Root(int x) {
    	if (rt[x] == x) return x;
    	return rt[x] = Root(rt[x]); 
    }
    void Merge(Node &S, Node L, Node R, int mid) {
    	S.cnt = L.cnt + R.cnt;
    	memcpy(S.l, L.l, sizeof S.l);
    	memcpy(S.r, R.r, sizeof S.r);
    	for (int i = 1; i <= n; ++i) {
    		rt[L.l[i]] = L.l[i];
    		rt[L.r[i]] = L.r[i];
    		rt[R.l[i]] = R.l[i];
    		rt[R.r[i]] = R.r[i];
    	}
    	for (int i = 1; i <= n; ++i) 
    		if (a[i][mid] == a[i][mid + 1] && Root(L.r[i]) != Root(R.l[i])) 
    			rt[Root(L.r[i])] = Root(R.l[i]), --S.cnt;
    	for (int i = 1; i <= n; ++i) S.l[i] = Root(S.l[i]), S.r[i] = Root(S.r[i]);
    }
    void Build(int x, int l, int r) {
    	if (l == r) {
    		for (int i = 1; i <= n; ++i) {
    			if (a[i][l] == a[i - 1][l]) s[x].l[i] = s[x].l[i - 1];
    			else s[x].l[i] = ++tot, ++s[x].cnt;
    			s[x].r[i] = s[x].l[i];
    		}
    		return;
    	}
    	int mid = l + r >> 1;
    	Build(x << 1, l, mid);
    	Build(x << 1 | 1, mid + 1, r);
    	Merge(s[x], s[x << 1], s[x << 1 | 1], mid);
    }
    void Query(int x, int l, int r, int L, int R) {
    	if (R < l || r < L) return;
    	if (L <= l && r <= R) {
    		if (!ans.cnt) ans = s[x];
    		else Merge(ans, ans, s[x], l - 1);
    		return;
    	}
    	int mid = l + r >> 1;
    	Query(x << 1, l, mid, L, R);
    	Query(x << 1 | 1, mid + 1, r, L, R); 
    }
    int main() {
    	Read(n), Read(m), Read(q);
    	for (int i = 1; i <= n; ++i) for (int j = 1; j <= m; ++j) Read(a[i][j]);
    	Build(1, 1, m);
    	int l, r;
    	while (q--) {
    		Read(l), Read(r);
    		ans.cnt = 0;
    		memset(ans.l, 0, sizeof ans.l);
    		memset(ans.r, 0, sizeof ans.r);
    		Query(1, 1, m, l, r);
    		Write(ans.cnt), putchar('
    ');
    	}
    	return 0;
    }
    
  • 相关阅读:
    [转] word2vec
    跨平台踩的一个大坑!
    在C 与 C++混编中, 出现error LNK2019: 无法解析的外部符号 "int __cdecl main_(int,char * *)" (?main_@@YAHHPEAPEAD@Z),该符号在函数 main 中被引用
    opencv2corecuda.hpp(106): error C2059: 语法错误:“常量”
    opencv2flannmatrix.h(69): error C2059: 语法错误:“,”
    C调用C++, C++调用C方法
    python与C,在写程序时踩过的坑!
    VS2015 + OPENCV + CUDA 安装流程
    CC++学习笔记 3
    CC++学习笔记 2
  • 原文地址:https://www.cnblogs.com/kcn999/p/14238146.html
Copyright © 2011-2022 走看看