• HDU5367 思维map // 动态线段树


    地主毛毛有n座山,这些山在地主家门前排成一条直线。这些山一开始均有相同的高度。  每一天,毛毛都会要求花花开挖机把几座山挖掉一定高度,或者给一些山堆上一些高度。并且要求花花报告现在有多少座山属于“高山脉”
    当一排山的高度相等,并且比这排山左边和右边的山要高时,这排山被称为高山脉。
    当然,最左边和最右边的山不可能是“高山脉”的一部分
     

    这题乍一看可以用线段树做,事实上确实可以用线段树做,但是在仔细思考,讨论出所有情况之后发现可以修改端点代替修改区间的方法来AC

    也就是说,将每次修改的L和R变为修改单点,用一次solve来将L之后的所有山全部加上v,再用一次solve来将R + 1之后的山高度全部减去R,在修改的过程中利用map来修改ans可以实现题目要求的在线

    1.map的AC代码

    #include <map>
    #include <set>
    #include <cmath>
    #include <queue>
    #include <stack>
    #include <vector>
    #include <string>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <sstream>
    #include <iostream>
    #include <algorithm>
    #include <functional>
    #define For(i, x, y) for(int i=x; i<=y; i++)  
    #define _For(i, x, y) for(int i=x; i>=y; i--)
    #define Mem(f, x) memset(f, x, sizeof(f))  
    #define Sca(x) scanf("%d", &x)
    #define Scl(x) scanf("%lld",&x);  
    #define Pri(x) printf("%d
    ", x)
    #define Prl(x) printf("%lld
    ",x);  
    #define CLR(u) for(int i = 0; i <= N ; i ++) u[i].clear();
    #define LL long long
    #define ULL unsigned long long  
    #define mp make_pair
    #define PII pair<int,int>
    #define PIL pair<int,long long>
    #define PLL pair<long long,long long>
    #define pb push_back
    #define fi first
    #define se second 
    using namespace std;
    typedef vector<int> VI;
    const double eps = 1e-9;
    const int maxn = 110;
    const int INF = 0x3f3f3f3f;
    const int mod = 1e9 + 7; 
    inline int read()
    {
        int now=0;register char c=getchar();
        for(;!isdigit(c);c=getchar());
        for(;isdigit(c);now=now*10+c-'0',c=getchar());
        return now;
    }
    int N,Q,R;
    int ans = 0;
    map<int,int>P;
    void solve(int mid,int v){
        if(!v)return;
        map<int,int> ::iterator  it,l,r;
        //cout << mid << "  " << P[mid] <<endl;
        if(P[mid] == 0){
            l = r = it = P.find(mid);     //这一步要放在if里面 
            l--,r++;                  
            if(l->se > 0 && r->se > 0 && v < 0){
                ans += (mid - l->fi);
            //    cout << l->fi << "  " << it->fi <<  "  " << r->fi << endl;
            }else if(l->se > 0 && r->se < 0 && v < 0){
                ans -= (r->fi - mid);
            }else if(l->se < 0 && r->se < 0 && v > 0){
                ans += (r->fi - mid);
            }else if(l->se > 0 && r->se < 0 && v > 0){
                ans -= mid - l->fi;
            }
            P[mid] = v;
        }else{
            l = r = it = P.find(mid);
            l--,r++;
            if(r == P.end() || it == P.begin()) return;    //对最左端和最右端的更新 
            if(l->se > 0 && r->se > 0 && it->se < 0){
                ans -= mid - l->fi;
            }else if(l->se < 0 && r->se < 0 && it->se > 0){
                ans -= r->fi - mid; 
            }else if(l->se > 0 && r->se < 0 && it->se < 0){
                ans += r->fi - mid;
            }else if(l->se > 0 && r->se < 0 && it->se > 0){
                ans += mid - l->fi;
            }
        //    cout << it->fi << "  " << it->se << endl;
            v += it->se;
            P.erase(it);
            solve(mid,v);
        }
    }
    int main()
    {
        while(~scanf("%d%d%d",&N,&Q,&R)){
            P.clear();
            P[1] = -INF; P[N + 1] = INF;
            ans = 0;
            while(Q--){
                int l,r,v;
                scanf("%d%d%d",&l,&r,&v);
                l ^= ans; r ^= ans; v ^= ans;
                solve(l,v);
                solve(r + 1,-v);
                Pri(ans);
            }
        }
        return 0;
    }

    2.有了以上的算法,从实现难度上来讲线段树就不算是最优解了,但是对练习线段树的写法也有一定意义,所以我用线段树也实现了一次。

    由于N大到1e9次,就不能像普通线段树一样直接build建树,要通过动态加点,也就是说只开辟使用到的区间的空间,由于查询只有50000次,仅仅开辟使用的空间并不会导致mle,学习了一手动态线段树的写法,这就很舒服

    这次线段树的难度主要在于pushup的实现上已经怎么想到维护的点,去维护什么东西,还有动态线段树的实现

    以下是动态线段树的代码

    #include <map>
    #include <set>
    #include <cmath>
    #include <queue>
    #include <stack>
    #include <vector>
    #include <string>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <sstream>
    #include <iostream>
    #include <algorithm>
    #include <functional>
    #define For(i, x, y) for(int i=x; i<=y; i++)  
    #define _For(i, x, y) for(int i=x; i>=y; i--)
    #define Mem(f, x) memset(f, x, sizeof(f))  
    #define Sca(x) scanf("%d", &x)
    #define Scl(x) scanf("%lld",&x);  
    #define Pri(x) printf("%d
    ", x)
    #define Prl(x) printf("%lld
    ",x);  
    #define CLR(u) for(int i = 0; i <= N ; i ++) u[i].clear();
    #define LL long long
    #define ULL unsigned long long  
    #define mp make_pair
    #define PII pair<int,int>
    #define PIL pair<int,long long>
    #define PLL pair<long long,long long>
    #define pb push_back
    #define fi first
    #define se second 
    using namespace std;
    typedef vector<int> VI;
    const double eps = 1e-9;
    const int maxn = 100010;
    const int INF = 0x3f3f3f3f;
    const int mod = 1e9 + 7; 
    inline int read()
    {
        int now=0;register char c=getchar();
        for(;!isdigit(c);c=getchar());
        for(;isdigit(c);now=now*10+c-'0',c=getchar());
        return now;
    }
    int ans;
    int N,Q,R;
    struct Tree{
        int lt,rt;
        int sum;  //高山脉的数目
        int lsum,rsum;   //左右起高度相同的山脉
        int lh,rh;   //左右山脉的高度
        int ll,rr; //左右第一个不连续山脉的高度
        int lazy; 
        void init(int l,int r){
            sum = lh = rh = ll = rr = lazy = lt = rt = 0;
            lsum = rsum = r - l + 1;
        }
    }tree[maxn * 100];
    int tot;
    void check(int &t,int l,int r){
        if(t) return;
        t = ++tot;
        tree[t].init(l,r);
        if(l == 1) tree[t].ll = INF;
        if(r == N) tree[t].rr = INF;
    }
    void add(int t,int val){
        tree[t].lazy += val;
        tree[t].ll += val; tree[t].rr += val;
        tree[t].lh += val; tree[t].rh += val;
    }
    void Pushdown(int t,int l,int r){
        if(tree[t].lazy){
            int m = (l + r) >> 1;
            check(tree[t].lt,l,m);
            check(tree[t].rt,m + 1,r);
            add(tree[t].rt,tree[t].lazy);
            add(tree[t].lt,tree[t].lazy);
            tree[t].lazy = 0;
        }
    }
    void Pushup(int t,int l,int r){
        int m = (l + r) >> 1;
        int lt = tree[t].lt;
        int rt = tree[t].rt;
        check(lt,l,m); check(rt,m + 1,r);
        tree[t].sum = tree[lt].sum + tree[rt].sum;
        tree[t].lsum = tree[lt].lsum; tree[t].rsum = tree[rt].rsum;
        tree[t].lh = tree[lt].lh; tree[t].rh = tree[rt].rh;
        tree[t].ll = tree[lt].ll; tree[t].rr = tree[rt].rr;
        if(tree[lt].rh == tree[rt].lh){
            if(tree[lt].rh > tree[lt].rr && tree[rt].ll < tree[rt].lh){
                tree[t].sum += tree[lt].rsum + tree[rt].lsum;
            }
            if(tree[lt].rsum == m - l + 1){
                tree[t].lsum += tree[rt].lsum;
                tree[t].ll = tree[rt].ll;
            }
            if(tree[rt].lsum == r - m){
                tree[t].rsum += tree[lt].rsum;
                tree[t].rr = tree[lt].rr;
            }
        }else{
            int lson = lt; int rson = rt;
            if(tree[lson].lsum == m - l + 1){
                tree[t].ll = tree[rson].lh;
            }
            if(tree[lson].rh > tree[rson].lh && tree[lson].rh > tree[lson].rr){
                tree[t].sum += tree[lson].rsum;
            }
            if(tree[rson].rsum == r - m){
                tree[t].rr = tree[lson].rh;
            }
            if(tree[rson].lh > tree[lson].rh && tree[rson].lh > tree[rson].ll){
                tree[t].sum += tree[rson].lsum;
            }
        }
    }
    void update(int &t,int l,int r,int L,int R,int val){
        check(t,l,r);
        if(L <= l && r <= R){
            add(t,val);
            return;
        }
        Pushdown(t,l,r);
        int m = (l + r) >> 1;
        if(L <= m) update(tree[t].lt,l,m,L,R,val);
        if(R > m) update(tree[t].rt,m + 1,r,L,R,val);
        Pushup(t,l,r);
    }
    int main()
    {
        while(~scanf("%d%d%d",&N,&Q,&R)){
            ans = 0;
            tot = 0;
            int root = 0;
            while(Q--){
                int l,r,val;
                scanf("%d%d%d",&l,&r,&val);
                l ^= ans; r ^= ans; val ^= ans;
                if(l > r) swap(l,r);
                update(root,1,N,l,r,val);
                ans = tree[root].sum;
                Pri(ans);
            }
        }
        return 0;
    }
     
  • 相关阅读:
    套接字描述符在多进程和多线程下的共享
    广播和多播
    原始套接字和数据链路层访问
    Libevent:11使用Libevent的DNS上层和底层功能
    Lib1vent:10链接监听器接受TCP链接
    Libevent:9Evbuffers缓存IO的实用功能
    Libevent:7Bufferevents基本概念
    python生成url测试用例
    OMD开源监控软件
    iptable防范ddos攻击
  • 原文地址:https://www.cnblogs.com/Hugh-Locke/p/9499686.html
Copyright © 2020-2023  润新知