51nod 1376 線段樹維護區間最大值

2022-02-28 22:46:17 字數 1670 閱讀 2962

引自:wonter巨巨的部落格

定義 dp[i] := 以數字 i(不是下標 i)為結尾的最長上公升長度

然後用線段樹維護 dp[i]:

每個節點維護 2 個資訊,乙個是當前區間的最大上公升長度,乙個是最大上公升長度的方案數,

這裡再詳細說下這篇題解。。。也是弱弱自己的理解吧。。。

以1-n的值為線段樹所代表的區間;

然後依次更新,題目就是要找上公升序列,那麼我們只要每次查詢0~arr[i]-1範圍內最長的那個長度和方案拿出來;

然後再去0到n區間裡更新,更新的值是arr[i],長度為查詢到的x+1,方案還是查詢到的方案y;

具體查詢:

我們是想知道在一段區間(從0到值arr[i]-1,這裡一定要注意是值!是值!)的最長長度;

所以一直查詢到那個區間,然後一直下去就好了;

中間如果出現被mid是夾在被查詢區間中間的話,就要比較一下左右兩段區間的最長長度

具體更新:

一直要先更新到最底;

然後再往上更新,

往上更新只要比較一下左右子區間的長度就好了;

#include using namespace std;

const int n=5e5+10;

const int mod=1e9+7;

struct asd;

asd q[n*4];

void build(int i,int left,int right)

void query(int i, int left, int right, int &x, int &y )

if(right<=q[i].mid)

if(left>q[i].mid)

int lx,ly;

int rx,ry;

query(i*2,left,q[i].mid,lx,ly);

query(i*2+1,q[i].mid+1,right, rx,ry);

if(lx==rx)

else if(lx>rx)

else

}void update(int i,int p,int x,int y)

else if(x==q[i].val)

return;

}if(p<=q[i].mid)

update(i*2,p,x,y);

else if(p>q[i].mid)

update(i*2+1,p,x,y);

if(q[i*2].val==q[i*2+1].val)

else if(q[i*2].val>q[i*2+1].val)

else

}int n;

int arr[n];

vectorxs;

int main()

sort(xs.begin(),xs.end());

auto e=unique(xs.begin(),xs.end());

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

arr[i]=lower_bound(xs.begin(), e, arr[i])-xs.begin()+1;

build(1,0,n);

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

int x,y;

query(1,0,n,x,y);

printf("%d\n",y);

return 0;

}

51nod1376 最長遞增子串行的數量

51nod1376 最長遞增子串行的數量 好題。首先nlgn的方法求以每個位置的數為結尾的最長遞增子串行,記為dp i 顯然dp值為x的數的答案數是由dp值為x 1的數貢獻的。例如現在要求dp值為x的數i的答案數,從dp值為x 1的數中找乙個數j,當滿足j的座標小於i,且j的值小於i的值時j的答案數...

51nod1376 最長遞增子串行的數量

這道題很sb,但是絕大多數人是用了高階資料結構的,我這裡介紹一種 自己yy的 不需要高階資料結構的方法。這道題不需要高階資料結構,考慮一開始的二分的方法,當我們們做到i時,我們維護的這個單調的序列的第j個位置表示的是 以min,a x 為原序列,其中以x結尾的lis的長度為j.考慮在這個單調序列的每...

51nod 1672 區間交(線段樹)

1672 區間交 基準時間限制 1 秒 空間限制 131072 kb 分值 40 難度 4級演算法題 小a有乙個含有n個非負整數的數列與m個區間,每個區間可以表示為li,ri。它想選擇其中k個區間,使得這些區間的交的那些位置所對應的數的和最大。是指k個區間共同的交,即每個區間都包含這一段,具體可以參...