您的位置:首页 > 其它

[Poi2010]Monotonicity 2 线段树

2017-07-27 20:32 344 查看
这道题考试的时候先打了个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 2020200
int a
,n,k;
char s
;
int cun
,f
;
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
;
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  动态规划