LP3246 [HNOI2016]序列 [莫队/笛卡尔树]

Author Avatar
空気浮遊 2018年10月11日
  • 在其它设备中阅读本文章

Problem

https://www.luogu.org/problemnew/show/P3246

Solution

用笛卡尔树水了 40 分...

正解是莫队 +dp 啥的...

Code 40pts

// Code by ajcxsu
// Problem: seg

#include<bits/stdc++.h>
using namespace std;

const int N=1e5+10;
int arr[N];
struct Node *nil;
struct Node {
    Node *ch[2];
    int id, val, l, r;
    Node(int id=0, int val=0):id(id), val(val) { ch[0]=ch[1]=nil; }
} *rt, po[N];
void ini() { nil=po, nil->ch[0]=nil->ch[1]=nil, nil->l=0x3f3f3f3f, nil->r=-0x3f3f3f3f; }

Node *stk[N];
int t;
int n, q;
void build() {
    for(int i=1;i<=n;i++) {
        while(t && stk[t]->val>=po[i].val) po[i].ch[0]=stk[t], t--;
        stk[++t]=po+i;
        if(t==1) rt=stk[t];
        else stk[t-1]->ch[1]=stk[t];
    }
}

void dfs(Node *x) {
    if(x==nil) return;
    if(x->ch[0]==nil && x->ch[1]==nil) x->l=x->r=x->id;
    else dfs(x->ch[0]), dfs(x->ch[1]), x->l=min(x->ch[0]->l, x->id), x->r=max(x->id, x->ch[1]->r);
}

typedef long long ll;
ll ans=0;
int query(Node *x, int xl, int xr) {
    int sl=1, sr=1;
    if(xl<=x->ch[0]->r) sl+=query(x->ch[0], xl, xr);
    if(xr>=x->ch[1]->l) sr+=query(x->ch[1], xl, xr);
    if(x->id>=xl && x->id<=xr) ans+=1ll*x->val*sl*sr, sr++;
    return sl+sr-2;
}

void check(Node *x) {
    if(x==nil) return;
    check(x->ch[0]), cout<<x->id<<' '<<x->l<<' '<<x->r<<endl, check(x->ch[1]);
}

int main() {
    ios::sync_with_stdio(false), cin.tie(0), ini();
    cin>>n>>q;
    for(int i=1;i<=n;i++) cin>>arr[i], po[i]=Node(i, arr[i]);
    build();
    dfs(rt);
    int l, r;
    while(q--) {
        cin>>l>>r, ans=0;
        query(rt, l, r), cout<<ans<<endl;
    }
    return 0;
}

Code

// Code by ajcxsu
// Problem: seg_true

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const int N=1e5+10;
int arr[N], pre[N], pos[N];
ll f[N], f2[N];
struct Query { int l, r, id; } qu[N];
bool cmp(const Query &a, const Query &b) { return pos[a.l]==pos[b.l]?a.r<b.r:a.l<b.l; }

const int OP=20;
int mi[N][OP], pi[N][OP];
int n, q, na;
void build() {
    for(int i=1;i<=n;i++) mi[i][0]=arr[i], pi[i][0]=i;
    for(int j=1;j<OP;j++)
        for(int i=1;i+(1<<j)-1<=n;i++) {
            if(mi[i][j-1]<mi[i+(1<<j-1)][j-1]) mi[i][j]=mi[i][j-1], pi[i][j]=pi[i][j-1];
            else mi[i][j]=mi[i+(1<<j-1)][j-1], pi[i][j]=pi[i+(1<<j-1)][j-1];
        }
}
int lo[N];
int query(int l, int r) {
    int len=lo[r-l+1];
    // assert(lo[r-l+1]==(int)log2(r-l+1));
    // cout<<l<<' '<<r<<' '<<(mi[l][len]<mi[r-(1<<len)+1][len]?pi[l][len]:pi[r-(1<<len)+1][len])<<endl;
    return mi[l][len]<mi[r-(1<<len)+1][len]?pi[l][len]:pi[r-(1<<len)+1][len];
}

ll ans, tot[N];
int l, r;
void revisel(int x, int d) {
    int p=query(x, r);
    ans+=1ll*d*(1ll*arr[p]*(r-p+1)+f2[x]-f2[p]);
}
void reviser(int x, int d) {
    int p=query(l, x);
    ans+=1ll*d*(1ll*arr[p]*(p-l+1)+f[x]-f[p]);
}

int main() {
    for(int i=2;i<N;i<<=1) lo[i]++;
    for(int i=2;i<N;i++) lo[i]+=lo[i-1];
    ios::sync_with_stdio(false), cin.tie(0);
    cin>>n>>q;
    for(int i=1;i<=n;i++) cin>>arr[i];
    for(int i=1;i<=n;i++) {
        na=i-1;
        while(na && arr[na]>=arr[i]) na=pre[na];
        pre[i]=na;
    }
    for(int i=1;i<=n;i++) f[i]=f[pre[i]]+1ll*arr[i]*(i-pre[i]);
    reverse(arr+1, arr+1+n);
    for(int i=1;i<=n;i++) {
        na=i-1;
        while(na && arr[na]>=arr[i]) na=pre[na];
        pre[i]=na;
    }
    for(int i=1;i<=n;i++) f2[i]=f2[pre[i]]+1ll*arr[i]*(i-pre[i]);
    reverse(arr+1, arr+1+n), reverse(f2+1, f2+1+n), build();
    int unit=sqrt(n);
    for(int i=1;i<=n;i++) pos[i]=i/unit;
    for(int i=1;i<=q;i++) cin>>qu[i].l>>qu[i].r, qu[i].id=i;
    sort(qu+1, qu+1+q, cmp);
    l=1, r=1, ans=arr[1];
    for(int i=1;i<=q;i++) {
        while(r<qu[i].r) reviser(r+1, 1), r++;
        while(r>qu[i].r) reviser(r, -1), r--;
        while(l<qu[i].l) revisel(l, -1), l++;
        while(l>qu[i].l) revisel(l-1, 1), l--;
        tot[qu[i].id]=ans;
    }
    for(int i=1;i<=q;i++) cout<<tot[i]<<endl;
    return 0;
}