Loj3033 JOISC 2019 Day2两个天线

下午唯一听懂的题目但,但还是比较模糊.写一篇题解来加深一下印象.
题目大意:给定\(n\)根天线,第\(i\)跟天线的高度为\(h_i\),切它能和与他距离在\([a_i,b_i]\)内的天线交流.
两根天线互相交流当且仅当他们彼此都在对方的交流范围内.定义两根天线交流的代价为\(|H_i-H_j|\)
\(Q\)次询问,每次询问区间\([l,r]\)内所有够相互交流的天线的交流代价的最大值(\(n <= 2*10^5\))

首先看到这种东西,我的第一反应是CDQ分治,但是CDQ分治不好处理这种多组区间询问的问题
所以只能另想办法
发现如果我们对于每个\(j\),都去寻找前面的一个\(i\)去和它匹配的话.那么\(j\)\(i\)的影响范围内当且仅当\(j\in[i+a_i,i+b_i]\)
也就是说,我们要想办法让\(i\)\(i+a_i\)处开始有贡献,在\(i + b_i + 1\)处失去贡献.这就会想到线段树扫描线,我们每个节点维护一个\(c_i\),当我们枚举到\(i+a_i\)时,就讲线段树上第\(i\)个位置的\(c_i\)变为\(h_i\),当离开这个区间时,就将其变为\(-\infty\)
这样我们就处理好了第一个问题:如何确保\(j\)\(i\)的交流范围内
接下来看第二个问题,如何确保\(i\)\(j\)的范围内并且统计答案
首先,\(|h_i-h_j|\)这个东西,我们可以讲它拆成\(h_i-h_j\)\(h_j-h_i\)就好了我们只考虑\(h_i-h_j\),另一个可以将值域翻转来考虑.
那么我们设\(d_i\)表示第\(i\)的天线和右边的匹配的最大代价这个东西可以直接在线段树上维护
而.\(di=h_i+max(-h_j)\)
那么我们对于每个\(j\),它能影响的之前的区间是\([i - b_i,i-a_i]\)(特判一下负数)
我们在在线段树上维护一个\(tag\),表示\(max(-hj)\)
那么扫到\(j\)时,就相当于在\([i - b_i,i-a_i]\)\(tag\)\(-h_j\)取max,这也是线段树能完成的
最后对于每个查询,扫到\(r_i\)时计算\([l_i,r_i]\)的答案就好了
(SB的我\(n,m\)不分WA了一晚上)

#include<cstring>
#include<cstdio>
#include<iostream>
#include<vector>
#include<cctype>
#include<algorithm>
#define pii pair<int,int>
#define mk make_pair
using namespace std;
const int N = 5e5 + 3;
const int INF = 1e9 + 7;
int n,m,t;
struct node{
    int lc,rc;
    int d,c,tag;    
}a[N << 1];
struct U{
    int hi;
    int ai,bi;  
}b[N];
struct Q{
    int li,ri;  
}q[N];
int ans[N];
vector <pii> G1[N];
vector <int> G2[N];
inline int read(){
    int v = 0,c = 1;char ch = getchar();
    while(!isdigit(ch)){
        if(ch == '-') c = -1;
        ch = getchar();
    }
    while(isdigit(ch)){
        v = v * 10 + ch - 48;
        ch = getchar(); 
    }
    return v * c;
}
inline void pushup(int u){
    a[u].c = max(a[a[u].lc].c,a[a[u].rc].c);
    a[u].d = max(a[a[u].lc].d,a[a[u].rc].d);    
}
inline void build(int u,int l,int r){
    a[u].c = a[u].d = a[u].tag = -INF;
    if(l == r) return ;
    int mid = (l + r) >> 1;
    a[u].lc = ++t;build(a[u].lc,l,mid);
    a[u].rc = ++t;build(a[u].rc,mid + 1,r);
//  pushup(u);
}
inline void pushdown(int u,int l,int r){
    if(a[u].tag == -INF) return;
    a[a[u].lc].tag = max(a[a[u].lc].tag,a[u].tag);
    a[a[u].rc].tag = max(a[a[u].rc].tag,a[u].tag);
    a[a[u].lc].d = max(a[a[u].lc].d,a[a[u].lc].c + a[a[u].lc].tag);
    a[a[u].rc].d = max(a[a[u].rc].d,a[a[u].rc].c + a[a[u].rc].tag);
    a[u].tag = -INF;
}
inline void change(int u,int l,int r,int x,int v){
    if(l == r){
        a[u].tag = -INF;
        a[u].c = v;
        //a[u].d = max
        return;
    }
    pushdown(u,l,r);
    int mid = (l + r) >> 1;
    if(x <= mid) change(a[u].lc,l,mid,x,v);
    else change(a[u].rc,mid + 1,r,x,v);
    pushup(u);
}
inline void updata(int u,int l,int r,int ll,int rr,int v){
    if(l == ll && r == rr){
        a[u].tag = max(a[u].tag,v);
        a[u].d = max(a[u].d,a[u].c + a[u].tag);
        return ;
    }
    pushdown(u,l,r);
    int mid = (l + r) >> 1;
    if(rr <= mid) updata(a[u].lc,l,mid,ll,rr,v);
    else if(ll > mid) updata(a[u].rc,mid + 1,r,ll,rr,v);
    else {
        updata(a[u].lc,l,mid,ll,mid,v);
        updata(a[u].rc,mid + 1,r,mid + 1,rr,v); 
    }
    pushup(u);
}
inline int query(int u,int l,int r,int ll,int rr){
    if(l == ll && r == rr) return a[u].d;   
    pushdown(u,l,r);
    int mid = (l + r) >> 1;
    if(rr <= mid) return query(a[u].lc,l,mid,ll,rr);
    else if(ll > mid) return query(a[u].rc,mid + 1,r,ll,rr);
    else return max(query(a[u].lc,l,mid,ll,mid),
    query(a[u].rc,mid + 1,r,mid + 1,rr));
}
inline void work(){
    t = 1;
    build(1,1,n);   
    for(int i = 1;i <= n;++i){
        for(int j = 0;j < G1[i].size();++j)
        change(1,1,n,G1[i][j].first,G1[i][j].second?b[G1[i][j].first].hi:-INF);
        if(i - b[i].ai > 0) updata(1,1,n,max(1,i - b[i].bi),i - b[i].ai,-b[i].hi);
        for(int j = 0;j < G2[i].size();++j)
        ans[G2[i][j]] = max(ans[G2[i][j]],query(1,1,n,q[G2[i][j]].li,q[G2[i][j]].ri));
    }
}
int main(){
    n = read();
    for(int i = 1;i <= n;++i){
        b[i].hi = read(),b[i].ai = read(),b[i].bi = read();
        if(i + b[i].ai <= n) G1[i + b[i].ai].push_back(mk(i,1));
        if(i + b[i].bi + 1 <= n) G1[i + b[i].bi + 1].push_back(mk(i,0));
    }
    m = read();
    for(int i = 1;i <= m;++i){
        q[i].li = read();
        q[i].ri = read();
        G2[q[i].ri].push_back(i);   
    }
    for(int i = 1;i <= m;++i) ans[i] = -1;
    work();
//      for(int i = 1;i <= n;++i) printf("%d\n",ans[i]);
    for(int i = 1;i <= n;++i) b[i].hi = 1000000001 - b[i].hi;
    work();
    for(int i = 1;i <= m;++i) printf("%d\n",ans[i]);
    return 0;   
}