zoukankan      html  css  js  c++  java
  • 红绿 [线段树分治, 并查集]

    绿红绿



    color{red}{正解部分}

    [1,q_tot][1, q\_tot] 进行 线段树分治, 将每个 绿绿 的 影响区间分为 logq_totlog q\_tot 个区间散布在 线段树节点 中,

    其中 qtotq_tot 为询问的总数 .

    然后对 线段树 DFSDFS, 合并祖先链的和当前节点的绿绿集合 (使用类似归并排序的方法),

    由于代价只与 最大生气值 有关, 所以按 生气值 从小到大 排序, 从后往前加入 并查集, 直到有 敌对红红 不得不在一个集合里,

    这时保存当前节点贡献, 将数组截止到不合法的位置往下递归 (此时没有遍历到的 绿绿 已无法对答案造成贡献) .

    到根节点处统计答案, 时间复杂度 O(N2logN)O(N^2 log N)

    并查集维护方法详见 这道题 .


    color{red}{实现部分}

    • 注意判断有效区间是否合法 .
    • 并查集合并前需要判断是否有必要 .
    • 为什么代码注释处会 RERE 啊 .
    #include<bits/stdc++.h>
    #define reg register
    #define pb push_back
    
    int read(){
            char c;
            int s = 0, flag = 1;
            while((c=getchar()) && !isdigit(c))
                    if(c == '-'){ flag = -1, c = getchar(); break ; }
            while(isdigit(c)) s = s*10 + c-'0', c = getchar();
            return s * flag;
    }
    
    const int maxn = 2000005;
    
    int N;
    int M;
    int Q_;
    int q_cnt;
    int F[maxn];
    int Ans[maxn];
    int match[maxn];
    
    char Smp[5];
    
    struct Grn{ int a, b, l, r, v; } A[maxn];
    
    bool cmp(Grn x, Grn y){ return x.v < y.v; }
    
    std::vector <Grn> B[maxn << 2], P[maxn << 2], Tmp;
    
    struct Node{ int l, r; } T[maxn << 2];
    
    int Find(int x){ return F[x]==x?x:F[x]=Find(F[x]); }
    
    void Build(int k, int l, int r){
            T[k].l = l, T[k].r = r;
            if(l == r) return ; int mid = l+r >> 1;
            Build(k<<1, l, mid), Build(k<<1|1, mid+1, r);
    }
    
    void merge(int a, int b){
            int t1 = Find(a), t2 = Find(b);
            if(t1 == t2) return ;
            F[t1] = t2;
    }
    
    void Insert(int k, const Grn &aim){
            int l = T[k].l, r = T[k].r;
            if(aim.l <= l && r <= aim.r) return B[k].pb(aim), void(); 
            int mid = l+r >> 1;
            if(aim.l <= mid) Insert(k<<1, aim);
            if(aim.r > mid) Insert(k<<1|1, aim);
    }
    
    void DFS(int k){
            int l = T[k].l, r = T[k].r, res = 0;
            int t1 = 0, t2 = 0, len_1 = P[k>>1].size(), len_2 = B[k].size();
            Tmp.clear();
            while(t1 < len_1 && t2 < len_2){
                    if(P[k>>1][t1].v < B[k][t2].v) Tmp.pb(P[k>>1][t1 ++]);
                    else Tmp.pb(B[k][t2 ++]);
            }
            while(t2 < len_2) Tmp.pb(B[k][t2 ++]);
            while(t1 < len_1) Tmp.pb(P[k>>1][t1 ++]);
            for(reg int i = 1; i <= 2*N+1; i ++) F[i] = i, match[i] = 0;
    
            for(reg int i = Tmp.size()-1; i >= 0; i --){
                    int u = Tmp[i].a, v = Tmp[i].b;
                    if(Find(2*u) == Find(v*2-1)) continue ;
                    merge(u*2, v*2-1), merge(v*2, u*2-1);
                    P[k].pb(Tmp[i]);
                    if(Find(u*2) == Find(u*2-1) || Find(v*2) == Find(v*2-1)){
                            res = Tmp[i].v;
                            break ;
                    }
            }
    
    /*
            for(reg int i = Tmp.size()-1; i >= 0; i --){
                    Grn t = Tmp[i];
                    int a = t.a, b = t.b;
                    P[k].pb(Tmp[i]);
                    if(Find(a) == Find(b)){ res = t.v; break ; }
                    if(!match[a]) match[a] = b; 
                    else merge(match[a], b);
                    if(!match[b]) match[b] = a;
                    else merge(match[b], a);
            }
    */
    
            if(l == r) return Ans[l] = res, void();
            std::reverse(P[k].begin(), P[k].end());
            DFS(k<<1), DFS(k<<1|1);
    }
    
    int main(){
            N = read(), M = read(), Q_ = read();
            for(reg int i = 1; i <= M; i ++){
                    A[i].a = read(), A[i].b = read(), A[i].v = read();
                    A[i].l = 1, A[i].r = -1;
            }
            for(reg int i = 1; i <= Q_; i ++){
                    scanf("%s", Smp);
                    if(Smp[0] == 'D')  A[read()].r = q_cnt;
                    else if(Smp[0] == 'A'){
                            A[++ M].a = read(), A[M].b = read(), A[M].v = read();
                            A[M].l = q_cnt+1, A[M].r = -1;
                    }else q_cnt ++;
            }
            Build(1, 1, q_cnt); std::sort(A+1, A+M+1, cmp);
            for(reg int i = 1; i <= M; i ++){ 
                    if(A[i].r == -1) A[i].r = q_cnt;
                    if(A[i].l > A[i].r) continue ;
                    Insert(1, A[i]); 
            }
            DFS(1);
            for(reg int i = 1; i <= q_cnt; i ++) printf("%d
    ", Ans[i]);
            return 0;
    }
    
  • 相关阅读:
    (二)《机器学习》(周志华)第4章 决策树 笔记 理论及实现——“西瓜树”——CART决策树
    (一)《机器学习》(周志华)第4章 决策树 笔记 理论及实现——“西瓜树”
    python学习笔记——递归算法
    Python爬虫抓取东方财富网股票数据并实现MySQL数据库存储
    MySQL安装总是失败,提示缺少Visual Studio 2013 Redistributable
    Python爬虫简单实现之Q乐园图片下载
    Python爬虫之简单的图片获取
    Springboot启动,URL正确,但是报404
    Linux常用命令
    MYSQL常用的配置参数优化
  • 原文地址:https://www.cnblogs.com/zbr162/p/11822400.html
Copyright © 2011-2022 走看看