[BZOJ]2090: [Poi2010]Monotonicity 2
题解: LIS的变式版本 我们用两颗线段树和一个数组来维护 dp[i]表示以i结尾的最长满足条件的序列 转移的话 分情况转移 他可以是从 大于 小于 等于三个方向转移过来 然后取max即可 更新的话 已知dp[i]可以推出下一个符号 然后在对应的数据结构中更新即可
#include <algorithm> #include <iostream> #include <cstring> #include <cstdio> #include <vector> #include <stack> #include <queue> #include <cmath> #include <set> #include <map> #define mp make_pair #define pb push_back #define pii pair<int,int> #define link(x) for(edge *j=h[x];j;j=j->next) #define inc(i,l,r) for(int i=l;i<=r;i++) #define dec(i,r,l) for(int i=r;i>=l;i--) const int MAXN=5e5+10; const double eps=1e-8; #define ll long long using namespace std; struct edge{int t,v;edge*next;}e[MAXN<<1],*h[MAXN],*o=e; void add(int x,int y,int vul){o->t=y;o->v=vul;o->next=h[x];h[x]=o++;} ll read(){ ll x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} while(isdigit(ch))x=x*10+ch-'0',ch=getchar(); return x*f; } int n,k; int a[MAXN]; vector<int>vec; int base; int maxx1[MAXN<<2],maxx2[MAXN<<2],ans1,dp[MAXN],maxx3[MAXN]; char str[MAXN]; void update1(int rt,int l,int r,int t,int k){ maxx1[rt]=max(maxx1[rt],k); if(l==r)return ; int mid=(l+r)>>1; if(t<=mid)update1(rt<<1,l,mid,t,k); else update1(rt<<1|1,mid+1,r,t,k); } void query1(int rt,int l,int r,int ql,int qr){ if(ql>qr)return ; if(ql<=l&&r<=qr){ans1=max(ans1,maxx1[rt]);return ;} int mid=(l+r)>>1; if(ql<=mid)query1(rt<<1,l,mid,ql,qr); if(qr>mid)query1(rt<<1|1,mid+1,r,ql,qr); } void update2(int rt,int l,int r,int t,int k){ maxx2[rt]=max(maxx2[rt],k); if(l==r)return ; int mid=(l+r)>>1; if(t<=mid)update2(rt<<1,l,mid,t,k); else update2(rt<<1|1,mid+1,r,t,k); } void query2(int rt,int l,int r,int ql,int qr){ if(ql>qr)return ; if(ql<=l&&r<=qr){ans1=max(ans1,maxx2[rt]);return ;} int mid=(l+r)>>1; if(ql<=mid)query2(rt<<1,l,mid,ql,qr); if(qr>mid)query2(rt<<1|1,mid+1,r,ql,qr); } int main(){ n=read();k=read(); inc(i,1,n)a[i]=read(),vec.pb(a[i]); inc(i,1,k)scanf(" %c",&str[i]); sort(vec.begin(),vec.end()); base=unique(vec.begin(),vec.end())-vec.begin(); inc(i,1,n)a[i]=lower_bound(vec.begin(),vec.begin()+base,a[i])-vec.begin()+1; //maxx1 大于 maxx2 小于 maxx3 等于 inc(i,1,n){ dp[i]=maxx3[a[i]]+1; ans1=0;query1(1,1,base,a[i]+1,base);dp[i]=max(dp[i],ans1+1); ans1=0;query2(1,1,base,1,a[i]-1);dp[i]=max(dp[i],ans1+1); if(str[(dp[i]-1)%k+1]=='>')update1(1,1,base,a[i],dp[i]); else if(str[(dp[i]-1)%k+1]=='<')update2(1,1,base,a[i],dp[i]); else maxx3[a[i]]=max(maxx3[a[i]],dp[i]); } int ans=0; inc(i,1,n)ans=max(ans,dp[i]); printf("%d\n",ans); }
2090: [Poi2010]Monotonicity 2
Time Limit: 30 Sec Memory Limit: 259 MBSubmit: 311 Solved: 167
[Submit][Status][Discuss]
Description
给出N个正整数a[1..N],再给出K个关系符号(>、<或=)s[1..k]。
选出一个长度为L的子序列(不要求连续),要求这个子序列的第i项和第i+1项的的大小关系为s[(i-1)mod K+1]。
求出L的最大值。
Input
第一行两个正整数,分别表示N和K (N, K <= 500,000)。
第二行给出N个正整数,第i个正整数表示a[i] (a[i] <= 10^6)。
第三行给出K个空格隔开关系符号(>、<或=),第i个表示s[i]。
Output
一个正整数,表示L的最大值。
Sample Input
7 3
2 4 3 1 3 5 3
< > =
2 4 3 1 3 5 3
< > =
Sample Output
6