1. 程式人生 > >luogu4093 [HEOI2016/TJOI2016]序列

luogu4093 [HEOI2016/TJOI2016]序列

esp markdown include math cpp space std urn ins

因為一個變化只會變化一個值,所以
\(dp[i]=max(dp[j])+1,j<i,maxval_j \leq a[i], a[j] \leq minval_i\)
發現跟二維數點問題挺像,樹狀數組套線段樹爽一爽。

#include <iostream>
#include <cstdio> 
using namespace std;
int n, m, zdz[100005], zxz[100005], a[100005], uu, vv, cnt, dp[100005], ans, rot[100005];
struct Node{
    int l, r, zdz;
}nd[9000005];
int lb(int
x){ return x&-x; } void insert(int &o, int l, int r, int x, int k){ if(!o) o = ++cnt; if(l==r) nd[o].zdz = max(nd[o].zdz, k); else{ int mid=(l+r)>>1; if(x<=mid) insert(nd[o].l, l, mid, x, k); if(mid<x) insert(nd[o].r, mid+1, r, x, k); nd[o].zdz = max(nd[nd[o].l].zdz, nd[nd[o].r].zdz); } } int
query(int o, int l, int r, int x, int y){ if(!o) return 0; if(l>=x &&r<=y) return nd[o].zdz; else{ int mid=(l+r)>>1; int re=0; if(x<=mid) re = max(re, query(nd[o].l, l, mid, x, y)); if(mid<y) re = max(re, query(nd[o].r, mid+1, r, x, y)); return
re; } } int main(){ cin>>n>>m; for(int i=1; i<=n; i++){ scanf("%d", &a[i]); zdz[i] = zxz[i] = a[i]; } for(int i=1; i<=m; i++){ scanf("%d %d", &uu, &vv); zdz[uu] = max(zdz[uu], vv); zxz[uu] = min(zxz[uu], vv); } for(int i=1; i<=n; i++){ for(int j=zxz[i]; j; j-=lb(j)) dp[i] = max(dp[i], query(rot[j], 1, 100000, 1, a[i])); dp[i]++; ans = max(ans, dp[i]); for(int j=a[i]; j<=100000; j+=lb(j)) insert(rot[j], 1, 100000, zdz[i], dp[i]); } cout<<ans<<endl; return 0; }

luogu4093 [HEOI2016/TJOI2016]序列