zoukankan      html  css  js  c++  java
  • BZOJ 2243 树链剖分

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2243

    题意:中文题目

    思路:树链剖分。首先考虑求区间颜色段数的问题, 我们可以用线段树维护:区间左右端点(st,ed),区间颜色段数(val),懒惰标记(lazy:是否整个区间被染成同一种颜色),区间左右端点的颜色(lcolor,rcolor),然后在查询的时候如果当前区间的左子树的右端点的颜色等于右子树的左端点的颜色,那么查询答案要减一。由于树链剖分在查询时是有可能两端的分链一起向上爬的。所以我们在查询时需要记录两端上一次查询结果的deep小的那个点的颜色。如果当前查询的链和上一次查询的交接处位置颜色一致那么答案就要减一。 

    注意: 颜色可能为0

    #define _CRT_SECURE_NO_DEPRECATE
    #include<iostream>
    #include<cstring>
    #include<string>
    #include<algorithm>
    #include<stdio.h>
    #include<queue>
    #include<vector>
    #include<stack>
    #include<map>
    #include<set>
    #include<time.h>
    #include<cmath>
    #include<sstream>
    #include<assert.h>
    using namespace std;
    #define L(x) x<<1
    #define R(x) x<<1|1
    typedef long long int LL;
    const int inf = 0x3f3f3f3f;
    const LL INF = 0x3f3f3f3f3f3f3f3fLL;
    const int MAXN = 1e5 + 10;
    int head[MAXN], tot, cnt,value[MAXN];
    struct Edge{
        int to, next;
    }Edges[MAXN * 2];
    void add(int u, int v){
        Edges[tot].to = v;
        Edges[tot].next = head[u];
        head[u] = tot++;
    }
    int id[MAXN], son[MAXN], deep[MAXN], size[MAXN], fa[MAXN], reid[MAXN], top[MAXN];
    void Init(){
        tot = 0; cnt = 0;
        memset(head, -1, sizeof(head));
        memset(son, -1, sizeof(son));
    }
    void DFS1(int u, int p,int dep){
        fa[u] = p; size[u] = 1; deep[u] = dep;
        for (int i = head[u]; i != -1; i = Edges[i].next){
            if (Edges[i].to != p){
                DFS1(Edges[i].to, u,dep+1);
                size[u] += size[Edges[i].to];
                if (son[u] == -1 || size[Edges[i].to] > size[son[u]]){
                    son[u] = Edges[i].to;
                }
            }
        }
    }
    void DFS2(int u, int tp){
        id[u] = ++cnt; reid[id[u]] = u; top[u] = tp;
        if (son[u] == -1){ return; }
        DFS2(son[u], tp);
        for (int i = head[u]; i != -1; i = Edges[i].next){
            if (son[u] != Edges[i].to&&Edges[i].to != fa[u]){
                DFS2(Edges[i].to, Edges[i].to);
            }
        }
    }
    struct Node{
        int st, ed;
        int lazy,val, lcolor,rcolor;
        //懒惰标记,颜色段数,区间左右端点的颜色
    }Seg[MAXN * 4];
    void pushUp(int k){
        Seg[k].lcolor = Seg[L(k)].lcolor;
        Seg[k].rcolor = Seg[R(k)].rcolor; 
        Seg[k].val = Seg[L(k)].val + Seg[R(k)].val;
        if (Seg[L(k)].rcolor == Seg[R(k)].lcolor){
            Seg[k].val--;
        }
    }
    void pushDown(int k){
        //颜色可能等于0
        if (Seg[k].lazy!=-1){
            Seg[L(k)].val = 1;
            Seg[L(k)].lcolor = Seg[L(k)].rcolor = Seg[L(k)].lazy = Seg[k].lazy;
            Seg[R(k)].val = 1;
            Seg[R(k)].lcolor = Seg[R(k)].rcolor = Seg[R(k)].lazy = Seg[k].lazy;
            Seg[k].lazy = -1;
        }
    }
    void Build(int l, int r, int k){
        Seg[k].st = l; Seg[k].ed = r;  Seg[k].lazy = -1;
        if (l == r){
            Seg[k].val = 1;
            Seg[k].lcolor = Seg[k].rcolor = value[reid[l]];
            return;
        }
        int mid = (l + r) / 2;
        Build(l, mid, L(k)); Build(mid + 1, r, R(k));
        pushUp(k);
    }
    void Modify(int l,int r,int val,int k){ 
        if (Seg[k].st == l&&Seg[k].ed == r){
            Seg[k].lazy = Seg[k].lcolor = Seg[k].rcolor = val;
            Seg[k].val = 1;
            return;
        }
        pushDown(k);
        if (r <= Seg[L(k)].ed){
            Modify(l, r, val, L(k));
        }
        else if (l >= Seg[R(k)].st){
            Modify(l, r, val, R(k));
        }
        else{
            Modify(l, Seg[L(k)].ed, val, L(k));
            Modify(Seg[R(k)].st, r, val, R(k));
        }
        pushUp(k);
    }
    void Modify(int u, int v,int val){
        int f1 = top[u], f2 = top[v];
        while (f1 != f2){
            if (deep[f1] < deep[f2]){
                swap(f1, f2);
                swap(u, v);
            }
            Modify(id[f1], id[u], val,1);
            u = fa[f1]; f1 = top[u];
        }
        if (deep[u] > deep[v]){
            swap(u, v);
        }
        Modify(id[u], id[v],val, 1);
    }
    Node Query(int l, int r, int k){ 
    //求区间有多少段颜色。并且保存这段区间左端点和右端点的颜色
        if (Seg[k].st == l&&Seg[k].ed == r){
            return Seg[k];
        }
        Node ans;
        pushDown(k);
        if (r <= Seg[L(k)].ed){
            ans = Query(l, r, L(k));
        }
        else if (l >= Seg[R(k)].st){
            ans = Query(l, r, R(k));
        }
        else{
            Node ansL= Query(l, Seg[L(k)].ed, L(k)),ansR=Query(Seg[R(k)].st,r,R(k));
            ans.val = ansL.val + ansR.val;
            ans.lcolor = ansL.lcolor; ans.rcolor = ansR.rcolor;
            if (ansL.rcolor == ansR.lcolor){
                ans.val--;
            }
        }
        pushUp(k);
        return ans;
    }
    int Query(int u, int v){
        int ans = 0,Lrc=-1,Rlc=-1;
        //保存上次询问时两端区间查询时deep比较小的点的颜色,因为可能两端同时上升爬
        int f1 = top[u], f2 = top[v];
        while (f1 != f2){
            if (deep[f1] < deep[f2]){
                swap(f1, f2);
                swap(u, v);
                swap(Lrc, Rlc);
            }
            Node temp = Query(id[f1], id[u], 1);
            ans += temp.val - (Lrc == temp.rcolor);
            u = fa[f1]; f1 = top[u]; Lrc = temp.lcolor;
        }
        if (deep[u] > deep[v]){
            swap(u, v);
            swap(Lrc, Rlc);
        }
        Node temp = Query(id[u], id[v], 1);
        ans += temp.val - (temp.rcolor == Rlc) - (temp.lcolor == Lrc);
        return ans;
    }
    int main(){
    //#ifdef kirito
    //    freopen("in.txt", "r", stdin);
    //    freopen("out.txt", "w", stdout);
    //#endif
    //    int start = clock();
        int n,m;
        while (~scanf("%d%d",&n,&m)){
            Init();
            for (int i = 1; i <= n; i++){
                scanf("%d", &value[i]);
            }
            for (int i = 1; i < n; i++){
                int u, v;
                scanf("%d%d", &u, &v);
                add(u, v); add(v, u);
            }
            DFS1(1, 1, 0);  DFS2(1, 1); Build(1, n, 1);
            while (m--){
                char ope[10];
                int u, v, w;
                scanf("%s", ope);
                switch (ope[0]){
                case 'C': scanf("%d%d%d", &u, &v, &w); Modify(u, v, w); break;
                default: scanf("%d%d", &u, &v); printf("%d
    ", Query(u, v)); break;
                }
            }
        }
    //#ifdef LOCAL_TIME
    //    cout << "[Finished in " << clock() - start << " ms]" << endl;
    //#endif
        return 0;
    }
  • 相关阅读:
    【笔记】模电lesson04 晶体管
    [笔记]模电如何判断和识别二极管的正负极
    [笔记]模电用数字万用表判断三极管管脚
    【笔记】模电lesson06 放大电路分析方法I
    【笔记】模电lesson07 放大电路分析方法II
    【翻译】在Verilog设计中使用参数化模块库(Quartus II)(Verilog)
    【原创】DE2实验练习解答—lab5 Clocks and Timers 【Verilog】【Digital Logic】
    【笔记】模电lesson 02 常用半导体器件
    【翻译】modelsim指南 I 之基本仿真(digital logic)
    【原创】DE2 实验练习解答—lab 2:数字和显示(digital Logic)(DE2)
  • 原文地址:https://www.cnblogs.com/kirito520/p/6500817.html
Copyright © 2011-2022 走看看