引自: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個區間共同的交,即每個區間都包含這一段,具體可以參...