P8037 [COCI2015-2016#7] Prokletnik

来源:https://www.cnblogs.com/rgw2010/p/18355760
-Advertisement-
Play Games

二維差分 為什麼我為OI淚目?因為我菜得離譜...... 引入 一維差分用來O(1)修改區間,配合上一維首碼和就是O(N)的查詢區間和。 差分為首碼和的逆運算。 二維差分同理。 接下來這道題就用二維差分來解決。 \(例題:地毯>>\) 地毯 題目描述 在 \(n\times n\) 的格子上有 \( ...


思路:

首先考慮離線。

\(Min-nxt_i\) 表示下一個小於 \(a_i\) 處的位置,\(Max-nxt_i\) 表示下一個大於 \(a_i\) 處的位置。

那麼 \([l,r]\) 是魔法區間當且僅當:

  • \(r\)\([l,r]\) 的最大值,且 \(r < Min - nxt_l\)

  • \(r\)\([l,r]\) 的最小值,且 \(r < Max - nxt_l\)

再令 \(Min-pre_i\) 表示上一個小於 \(a_i\) 處的位置,\(Max-pre_i\) 表示上一個大於 \(a_i\) 處的位置。

那麼我們可以對於每個 \(r\),求出對應的 \(l\) 的氛圍:

  • \(r\)\([l,r]\) 的最大值,則 \(l \in [Max-pre_r+1,r]\)

  • \(r\)\([l,r]\) 的最小值,則 \(l \in [Min-pre_r+1,r]\)

則可以在掃描線掃到 \(r\) 時,對上述兩個區間更新答案;註意到對於 \(l\) 的答案是 \(r-l+1\),那麼對於區間 \([a,b]\),其的右端點若都是 \(r\),要使得貢獻最大,應該選擇 \([a,r]\) 區間,但是有些點是無法對 \(r\) 造成貢獻的(對於這類點的處理見下文),於是我們需要找到 \([a,b]\) 內最小的能對 \(r\) 造成貢獻的點,維護一個 set 二分即可,需要支持刪除。

但是我們需要滿足 \(r < Min-nxt_l\)\(r<Max-nxt_l\),那麼可以在 \(Min-nxt_l\)\(Max-nxt_l\) 處將 \(l\) 此處賦值為無窮小即可。

註意到就算 \(l\) 處被賦值為無窮小,即無法對 \(r\)\(r\) 後面的數造成貢獻,但是其本身也有貢獻,需要用另外一個線段樹維護無法造成新貢獻的點的區間最大貢獻。

時間複雜度為 \(O((N+Q) \log^2 N)\)

完整代碼:

#include<bits/stdc++.h>
#define Add(x,y) (x+y>=mod)?(x+y-mod):(x+y)
#define lowbit(x) x&(-x)
#define pi pair<ll,ll>
#define pii pair<ll,pair<ll,ll>>
#define iip pair<pair<ll,ll>,ll>
#define ppii pair<pair<ll,ll>,pair<ll,ll>>
#define fi first
#define se second
#define full(l,r,x) for(auto it=l;it!=r;it++) (*it)=x
#define Full(a) memset(a,0,sizeof(a))
#define open(s1,s2) freopen(s1,"r",stdin),freopen(s2,"w",stdout);
using namespace std;
typedef double db;
typedef unsigned long long ull;
typedef int ll;
bool Begin;
const ll N=5e5+10;
inline ll read(){
    ll x=0,f=1;
    char c=getchar();
    while(c<'0'||c>'9'){
        if(c=='-')
          f=-1;
        c=getchar();
    }
    while(c>='0'&&c<='9'){
        x=(x<<1)+(x<<3)+(c^48);
        c=getchar();
    }
    return x*f;
}
inline void write(ll x){
	if(x<0){
		putchar('-');
		x=-x;
	}
	if(x>9)
	  write(x/10);
	putchar(x%10+'0');
}
ll n,q,l,r,top;
ll a[N],ans[N],stk[N],Mi_pre[N],Ma_pre[N],Mi_nxt[N],Ma_nxt[N];
vector<ll> F[N],G[N];
vector<pi> Q[N];
class St{
public:
    ll X[N<<2];
    void pushup(ll k){
        X[k]=max(X[k<<1],X[k<<1|1]);
    }
    void build(ll k,ll l,ll r){
        X[k]=0;
        if(l==r)
          return ;
        ll mid=(l+r)>>1;
        build(k<<1,l,mid);
        build(k<<1|1,mid+1,r);
    }
    void add(ll k,ll l,ll r,ll i,ll v){
        if(l==i&&i==r){
            X[k]=v;
            return ;
        }
        ll mid=(l+r)>>1;
        if(i<=mid)
          add(k<<1,l,mid,i,v);
        else
          add(k<<1|1,mid+1,r,i,v);
        pushup(k);
    }
    ll query(ll k,ll L,ll R,ll l,ll r){
        if(L==l&&r==R)
          return X[k];
        ll mid=(L+R)>>1;
        if(r<=mid)
          return query(k<<1,L,mid,l,r);
        else if(l>mid)
          return query(k<<1|1,mid+1,R,l,r);
        else
          return max(query(k<<1,L,mid,l,mid),query(k<<1|1,mid+1,R,mid+1,r));
    }    
}TT;
class Tree{
public:
    set<ll> S;
    struct Node{
        ll l,r;
        ll Max;
        ll tag;
    }X[N<<2];
    ll get(ll x){
        return (*S.lower_bound(x));
    }
    void add(ll k,ll v){
        ll t=get(X[k].l);
        if(t>X[k].r)
          X[k].Max=-1e9;
        else
          X[k].Max=v-t+1;
        X[k].tag=v;
    }
    void push_down(ll k){
        if(X[k].tag){
            add(k<<1,X[k].tag);
            add(k<<1|1,X[k].tag);
            X[k].tag=0;
        }
    }
    void pushup(ll k){
        X[k].Max=max(X[k<<1].Max,X[k<<1|1].Max);
    }
    void build(ll k,ll l,ll r){
        X[k].l=l,X[k].r=r;
        X[k].tag=X[k].Max=0;
        if(l==r){
            S.insert(l);
            return ;
        }
        ll mid=(l+r)>>1;
        build(k<<1,l,mid);
        build(k<<1|1,mid+1,r);
    }
    void add(ll k,ll i,ll v){
        if(X[k].l==i&&i==X[k].r){
            TT.add(1,1,n,i,X[k].Max);
            S.erase(i);
            X[k].Max=v;
            return ;
        }
        push_down(k);
        ll mid=(X[k].l+X[k].r)>>1;
        if(i<=mid)
          add(k<<1,i,v);
        else
          add(k<<1|1,i,v);
        pushup(k);
    }
    void update(ll k,ll l,ll r,ll v){
        if(X[k].l==l&&r==X[k].r){
            //cerr<<"1:"<<l<<' '<<r<<' '<<v<<'\n';
            add(k,v);
            //cerr<<"2:"<<l<<' '<<r<<' '<<X[k].Max<<'\n';
            return ;
        }
        push_down(k);
        ll mid=(X[k].l+X[k].r)>>1;
        if(r<=mid)
          update(k<<1,l,r,v);
        else if(l>mid)
          update(k<<1|1,l,r,v);
        else{
            update(k<<1,l,mid,v);
            update(k<<1|1,mid+1,r,v);
        }
        pushup(k);
        //cerr<<"3:"<<X[k].l<<' '<<X[k].r<<' '<<X[k].Max<<'\n';
    }
    ll query(ll k,ll l,ll r){
        //cerr<<"4:"<<X[k].l<<' '<<X[k].r<<' '<<X[k].Max<<'\n';
        if(X[k].l==l&&r==X[k].r)
          return X[k].Max;
        push_down(k);
        ll mid=(X[k].l+X[k].r)>>1;
        if(r<=mid)
          return query(k<<1,l,r);
        else if(l>mid)
          return query(k<<1|1,l,r);
        else
          return max(query(k<<1,l,mid),query(k<<1|1,mid+1,r));
    }
}T;
bool End;
int main(){
    n=read();
    for(int i=1;i<=n;i++)
      a[i]=read();
    q=read();
    for(int i=1;i<=q;i++){
        l=read(),r=read();
        Q[r].push_back({l,i});
    }
    for(int i=1;i<=n;i++){
        while(top&&a[stk[top]]>a[i]){
            Mi_nxt[stk[top]]=i;
            top--;
        }
        stk[++top]=i;    
    }
    top=0;
    for(int i=1;i<=n;i++){
        while(top&&a[stk[top]]<a[i]){
            Ma_nxt[stk[top]]=i;
            top--;
        }
        stk[++top]=i;
    }
    top=0;
    for(int i=n;i>=1;i--){
        while(top&&a[stk[top]]>a[i]){
            Mi_pre[stk[top]]=i;
            top--;
        }
        stk[++top]=i;  
    }
    top=0;
    for(int i=n;i>=1;i--){
        while(top&&a[stk[top]]<a[i]){
            Ma_pre[stk[top]]=i;
            top--;
        }
        stk[++top]=i;       
    }
    for(int i=1;i<=n;i++){
        F[Mi_nxt[i]].push_back(i);
        G[Ma_nxt[i]].push_back(i);
    }
    T.build(1,1,n);
    TT.build(1,1,n);
    for(int i=1;i<=n;i++){
        for(auto v:F[i])
          T.add(1,v,-1e9);
        T.update(1,Ma_pre[i]+1,i,i);
        for(auto t:Q[i])
          ans[t.se]=max({ans[t.se],T.query(1,t.fi,i),TT.query(1,1,n,t.fi,i)});
    }
    T.build(1,1,n);
    TT.build(1,1,n);
    for(int i=1;i<=n;i++){
        for(auto v:G[i])
          T.add(1,v,-1e9);
        T.update(1,Mi_pre[i]+1,i,i);
        for(auto t:Q[i])
          ans[t.se]=max({ans[t.se],T.query(1,t.fi,i),TT.query(1,1,n,t.fi,i)});
    }
    for(int i=1;i<=q;i++){
        write(ans[i]);
        putchar('\n');
    }
	return 0;
}

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • title: 清除 Nuxt 狀態緩存:clearNuxtState date: 2024/8/7 updated: 2024/8/7 author: cmdragon excerpt: 摘要:本文介紹了Nuxt.js框架中clearNuxtState方法的使用,該方法用於清除useState管理的 ...
  • 前言 在一些特殊的場景中(比如低代碼、減少小程式包體積、類似於APP的熱更新),我們需要從服務端動態載入.vue文件,然後將動態載入的遠程vue組件渲染到我們的項目中。今天這篇文章我將帶你學會,在vue3中如何去動態載入遠程組件。 歐陽寫了一本開源電子書vue3編譯原理揭秘,這本書初中級前端能看懂。 ...
  • 電梯導航也被稱為錨點導航,當點擊錨點元素時,頁面內相應標記的元素滾動到視口。而且頁面內元素滾動時相應錨點也會高亮。電梯導航一般把錨點放在左右兩側,類似電梯一樣。常見的電梯導航效果如下,比如一些官方文檔中: 之前可能會用 getBoundingClientRect() 判斷元素是否在視口中來實現類似效 ...
  • CSS中span元素垂直居中【解決span元素內基線對齊問題】 在樣式的書寫中,我們常常使用以下方式實現垂直居中,若span元素內例外,解決辦法看文章最後 <div class="parent"> <span class="child">text</span> </div> 1.flex佈局方式垂直 ...
  • 元組是不可變的序列類型,可以包含不同類型的元素。命名元組是元組的子類,它允許你為元組中的位置指定名稱,從而使代碼更加清晰,本文主要介紹了兩種元組的使用方法和應用場景。 ...
  • 醫療行業解決方案互聯網醫院架構患者門戶:提供患者信息查詢、掛號、繳費等基本服務。 預約掛號:允許患者線上預約掛號,減少現場排隊等候時間。 掛號查詢:患者可以查詢掛號狀態和相關信息。 院內導診:提供院內導航服務,幫助患者快速找到診室或部門。 檢驗報告查詢:患者可以線上查詢檢驗結果。 檢查報告查詢:提供 ...
  • 寫在前面 前面講的是面向對象中的繼承思想,下麵讓我們來看看多態這部分的內容! Java 面向對象概念概述 多態 概述:某一個事物在不同狀態下的多種狀態。 實現多態的三大前提: 要有繼承關係。 要有方法的重寫。 要有父類的引用指向子類對象。 訪問成員的特點: 成員變數:編譯時看左,運行時看左。 成員方 ...
  • 2018年6月,大三暑假進行時 上班之前,我提前跟家裡人打過招呼了。 我說我已經拿到了實習的offer,明天就過去上班,離家裡很近,月薪3500,我騎自行車過去就行。 家裡人就說挺好的,讓我騎個電瓶車,這樣會快點,囑咐我好好乾。 這是我第一次正式上班,我還覺得挺神奇的,沒想到我都要上班了。 大學以前 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...