[Poi2010]Monotonicity 2 线段树

来源:互联网 发布:excel将数据分成多列 编辑:程序博客网 时间:2024/06/05 20:25

这道题考试的时候先打了个dfs暴力。又打了个O(n²)的动规。然后竟然心血来潮拍了一下。。明明知道过不去的。。。然后水了50分(20个测试点这么多啊啊啊啊)。

因为它已经提前给你如果长度为i时下一位的符号,显然O(n²)的打法大家都会打。

for(i..1..n)  for(j..1..i-1)     if(符合条件)       f[i]=max(f[i],f[j]+1);

然后我们就考虑如何降低复杂度。

因为我们要求的是符合条件的前缀最大值,可以使用线段树来维护。

线段树的下标是权值,内容是最长长度。

一共三种情况:<,>,=。

我们需要单独存这三种情况。以大于为例:

线段树里面存的是某个权值下,下一位是大于号的所有最优长度。

至于等于可以用数组记录,不必用线段树。

然后我们更新的时候,对于f[i]=max{权值(0,a[i]-1)中所有后边符号是小于的最大值,权值(a[i]+1,inf)中所有后边符号是大于的最大值,相等的最大值}+1;

再根据f[i]的长度确定后边一位是什么符号,再把f[i]加入对应的线段树中。

复杂度O(n㏒n)。

#include<cstdio>#include<cstring>#include<iostream>using namespace std;#define pos(i,a,b) for(int i=(a);i<=(b);i++)#define N 2020200int a[N],n,k;char s[N];int cun[N],f[N];int ans;int ma;struct haha{int left,right,num;};haha treeda[N*4];haha treexiao[N*4];void buildda(int x,int left,int right){treeda[x].left=left;treeda[x].right=right;if(left==right){treeda[x].num=0;return;}int mid=(left+right)>>1;buildda(x*2,left,mid);buildda(x*2+1,mid+1,right);}int queryda(int left,int right,int root){if(treeda[root].left==left&&treeda[root].right==right){return treeda[root].num;}int mid=(treeda[root].left+treeda[root].right)>>1;if(right<=mid){return queryda(left,right,root*2);}else{if(left>mid){return queryda(left,right,root*2+1);}else{return max(queryda(left,mid,root*2),queryda(mid+1,right,root*2+1));}}}void changeda(int x,int num,int root){if(treeda[root].left==treeda[root].right){treeda[root].num=num;return;}treeda[root].num=max(treeda[root].num,num);if(x<=treeda[root*2].right)  changeda(x,num,root*2);else  changeda(x,num,root*2+1);}void buildxiao(int x,int left,int right){treexiao[x].left=left;treexiao[x].right=right;if(left==right){treexiao[x].num=0;return;}int mid=(left+right)>>1;buildxiao(x*2,left,mid);buildxiao(x*2+1,mid+1,right);}int queryxiao(int left,int right,int root){if(treexiao[root].left==left&&treexiao[root].right==right){return treexiao[root].num;}int mid=(treexiao[root].left+treexiao[root].right)>>1;if(right<=mid){return queryxiao(left,right,root*2);}else{if(left>mid){return queryxiao(left,right,root*2+1);}else{return max(queryxiao(left,mid,root*2),queryxiao(mid+1,right,root*2+1));}}}void changexiao(int x,int num,int root){if(treexiao[root].left==treexiao[root].right){treexiao[root].num=num;return;}treexiao[root].num=max(treexiao[root].num,num);if(x<=treexiao[root*2].right)  changexiao(x,num,root*2);else  changexiao(x,num,root*2+1);}int deng[N];int Max(int a,int b,int c){return max(max(a,b),c);}int main(){//freopen("mot.in","r",stdin);//freopen("mot.out","w",stdout);scanf("%d%d",&n,&k);pos(i,1,n){scanf("%d",&a[i]);ma=max(ma,a[i]);}pos(i,1,k){scanf("%s",&s[i]);}pos(i,1,n-1){cun[i]=s[(i-1)%k+1];}buildxiao(1,0,ma);buildda(1,0,ma);pos(i,1,n){int tmp1,tmp2;if(a[i]==ma){tmp1=1;}else{tmp1=queryda(a[i]+1,ma,1);}if(a[i]==0){tmp2=1;}else{tmp2=queryxiao(0,a[i]-1,1);}f[i]=Max(tmp1,tmp2,deng[a[i]])+1;if(cun[f[i]]=='>'){changeda(a[i],f[i],1);}if(cun[f[i]]=='<'){changexiao(a[i],f[i],1);}if(cun[f[i]]=='='){deng[a[i]]=max(deng[a[i]],f[i]);}ans=max(ans,f[i]);}printf("%d",ans);return 0;}

原创粉丝点击