zoukankan      html  css  js  c++  java
  • codeforces 811 E. Vladik and Entertaining Flags(线段树+并查集)

    题目链接:http://codeforces.com/contest/811/problem/E

    题意:给定一个行数为10 列数10w的矩阵,每个方块是一个整数, 给定l和r 求范围内的联通块数量 所谓联通块即数字相等

    题解:显然可以用线段树来维护一下,一共就10行。线段树唯一难处理的就是push_up不好弄,这一要利用一下并查集,因为求的是连通块

    的个数。具体看一下代码的注释。

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    using namespace std;
    const int M = 1e5 + 10;
    struct TnT {
        int l , r , sum;
        int lsum[11] , rsum[11];
    }T[M << 2];
    int f[M << 4] , a[11][M];
    int n , m , q , tot;
    //并查集并的是她们连通块的种类。
    void init() {
        for(int i = 1 ; i <= n * m ; i++) {
            f[i] = i;
        }
    }
    int find(int x) {
        if(x == f[x]) return x;
        int tmp = find(f[x]);
        return f[x] = tmp;
    }
    TnT push_up(int mid , TnT le , TnT re) {
        TnT ans;
        ans.sum = le.sum + re.sum;
        for(int j = 1 ; j <= n ; j++) {
            f[le.lsum[j]] = le.lsum[j];
            f[le.rsum[j]] = le.rsum[j];
            f[re.lsum[j]] = re.lsum[j];
            f[re.rsum[j]] = re.rsum[j];
        }//这里一定要这样赋值一下因为合并的时候这两部分肯定不属于同意连通块,所以不能让她们的父亲相同,而且她们的父亲会在合并的时候变成相同的所以这里要每次给她们定一个新父亲。
        for(int j = 1 ; j <= n ; j++) {
            if(a[j][mid] == a[j][mid + 1]) {
                int t1 = find(le.rsum[j]) , t2 = find(re.lsum[j]);
                if(t1 != t2) {
                    ans.sum--;
                    f[t1] = t2;
                }//显然如果不是相同父亲的sum--
            }
        }
        for(int j = 1 ; j <= n ; j++) {
            ans.lsum[j] = find(le.lsum[j]);
            ans.rsum[j] = find(re.rsum[j]);
        }//pushup一下ans的lsum于rsum
        ans.l = le.l , ans.r = re.r;
        return ans;
    }
    void build(int i , int l , int r) {
        int mid = (l + r) >> 1;
        T[i].l = l , T[i].r = r , T[i].sum = 0;
        if(l == r) {
            for(int j = 1 ; j <= n ; j++) {
                if(a[j][l] == a[j - 1][l]) {
                    T[i].lsum[j] = T[i].rsum[j] = T[i].lsum[j - 1];//如果相邻两个一样那么她们肯定属于一个连通块所以连通块下表一样,
                }
                else {
                    T[i].lsum[j] = T[i].rsum[j] = ++tot;
                    T[i].sum++;
                }
            }
            return ;
        }
        build(i << 1 , l , mid);
        build((i << 1) | 1 , mid + 1 , r);
        T[i] = push_up(mid , T[i << 1] , T[(i << 1) | 1]);
    }
    TnT query(int i , int l , int r) {
        int mid = (T[i].l + T[i].r) >> 1;
        if(T[i].l == l && T[i].r == r) {
            return T[i];
        }
        T[i] = push_up(mid , T[i << 1] , T[(i << 1) | 1]);
        if(mid < l) return query((i << 1) | 1 , l , r);
        else if(mid >= r) return query(i << 1 , l , r);
        else {
            return push_up(mid , query(i << 1 , l , mid) , query((i << 1) | 1 , mid + 1 , r));
        }
    }
    int main() {
        scanf("%d%d%d" , &n , &m , &q);
        tot = 0;
        for(int i = 1 ; i <= n ; i++) {
            for(int j = 1 ; j <= m ; j++) {
                scanf("%d" , &a[i][j]);
            }
        }
        init();
        build(1 , 1 , m);
        while(q--) {
            int x , y;
            scanf("%d%d" , &x , &y);
            printf("%d
    " , query(1 , x , y).sum);
        }
        return 0;
    }
    
  • 相关阅读:
    mysql in 中使用子查询,会不使用索引而走全表扫描
    java集合之hashMap,初始长度,高并发死锁,java8 hashMap做的性能提升
    简要了解web安全之sql注入
    java之JVM学习--简单了解GC算法
    java之JVM学习--简单理解编译和运行的过程之概览
    java之JVM学习--基本机构
    JDK,JRE,JVM 关系和概念
    SpringAOP源码解析
    数据结构——实现list
    由数据库练习浅析子查询和链接查询
  • 原文地址:https://www.cnblogs.com/TnT2333333/p/6929540.html
Copyright © 2011-2022 走看看