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;
}
 
原文地址:https://www.cnblogs.com/Hugh-Locke/p/9499686.html