DBSDFZOJ 4844 區間(分治)

2021-08-16 08:04:21 字數 1397 閱讀 4466

可以發現對於詢問的區間,只有區間裡的最小值和最大值是有意義的。不妨把詢問原區間等效為詢問值域區間。

大題思路是在輸入時我們很容易知道想讓乙個連續區間包含這段詢問區間至少需要向左向右擴充套件到**,但是因為擴充套件時可能會改變區間的最大(小)值,所以我們找出到底擴充套件到**可以符合條件即可。

令輸入的序列為a。可以維護乙個st表讓我們在o(1)的複雜度內知道對於查詢的值域區間,最少需要向左(右)擴充套件到**。讓我們將a[i]和a[i+1]在i點一起考慮。考慮分治,先從小區間開始計算,每一層裡只考慮經過分治中點的區間(一定會包含所有區間),向左右擴充套件,維護最左最右端點直到不需要再擴充套件,那麼這個區間內的所有點的左右端點即為當前區間。當我們知道了每個點向左右擴充套件的端點,就可以用st表維護乙個區間的左右端點。時間複雜度o(n logn)。

#include

#define n 100005

using

namespace

std;

int n,m,a[n],tl[n],tr[n],al[n],ar[n],fl[n][20],fr[n][20],lg[n];

void solve(int l,int r)

else

if(jif(tl[j]if(tr[j]>r) r=tr[j];

++j;

}else

break;

}if(lbreak;

while(x>=i)

while(yif(al[y]if(ar[y]>j) ar[y]=j;

++y;}}

for(int i=mid,j=mid+1;j<=r;++j)

else

if(jif(tl[j]if(tr[j]>r) r=tr[j];

++j;

}else

break;

}if(lbreak;

while(x>=i)

while(yif(al[y]if(ar[y]>j) ar[y]=j;

++y;}}

}int main()

}for(int i=1;iint l=a[i],r=a[i+1];

if(l>r) swap(l,r);

int k=lg[r-l+1];

tl[i]=min(fl[l][k],fl[r-(1

<1][k]);

tr[i]=max(fr[l][k],fr[r-(1

<1][k]);

}solve(1,n);

p=lg[n-1];

for(int i=1;i0]=al[i],fr[i][0]=ar[i];

for(int i=1;i<=p;++i)

}scanf("%d",&m);

while(m--)

}return

0;}

7620 區間合併

7620 區間合併 總時間限制 1000ms 記憶體限制 65536kb 描述 給定 n 個閉區間 ai bi 其中i 1,2,n。任意兩個相鄰或相交的閉區間可以合併為乙個閉區間。例如,1 2 和 2 3 可以合併為 1 3 1 3 和 2 4 可以合併為 1 4 但是 1 2 和 3 4 不可以合...

4975 區間翻轉

小q和tangjz正在乙個長度為n的序列a 1,a 2,a n上玩乙個有趣的關於區間翻轉的遊戲。小q和tangjz輪流行動 小q先手。每次行動方玩家需要選擇乙個長度為4x 2或4x 3的區間 l,r 1 l r n 其中x是該玩家自行選擇 的非負整數,然後將a l,a a a r翻轉,例如1 3 2...

7620 區間合併

總時間限制 1000ms 記憶體限制 65536kb 描述 給定 n 個閉區間 ai bi 其中i 1,2,n。任意兩個相鄰或相交的閉區間可以合併為乙個閉區間。例如,1 2 和 2 3 可以合併為 1 3 1 3 和 2 4 可以合併為 1 4 但是 1 2 和 3 4 不可以合併。我們的任務是判斷...