您的位置:首页 > 其它

HDU 3308 (线段树区间合并)

2014-08-01 18:47 246 查看
http://acm.hdu.edu.cn/showproblem.php?pid=3308

题意: 两个操作 : 1 修改 单点 a 处的值。

2 求出 区间【a,b】内的最长上升子序列。

做法:线段树区间合并。了解线段树的具体含义很容易。

1 // by caonima
2 // hehe
3 #include <cstdio>
4 #include <cstring>
5 #include <algorithm>
6 #include <vector>
7 #include <cmath>
8 using namespace std;
9 const int MAX= 1e5+10;
int Lsum[MAX<<2],Rsum[MAX<<2],Msum[MAX<<2];
int Lnum[MAX<<2],Rnum[MAX<<2];
int a[MAX];
char Q[10];

void push_up(int o,int m) {
Lsum[o]=Lsum[o<<1];
Rsum[o]=Rsum[o<<1|1];
Msum[o]=max(Msum[o<<1],Msum[o<<1|1]);
Lnum[o]=Lnum[o<<1];
Rnum[o]=Rnum[o<<1|1];
if(Rnum[o<<1]<Lnum[o<<1|1]) {
if(Lsum[o<<1]==(m-(m>>1))) Lsum[o]+=Lsum[o<<1|1];
if(Rsum[o<<1|1]==(m>>1)) Rsum[o]+=Rsum[o<<1];
Msum[o]=max(Msum[o],Rsum[o<<1]+Lsum[o<<1|1]);
}
return ;
}

void build(int L,int R,int o) {
if(L==R) {
Lsum[o]=Rsum[o]=Msum[o]=1;
Lnum[o]=Rnum[o]=a[L];
return ;
}
int mid=(L+R)>>1;
build(L,mid,o<<1);
build(mid+1,R,o<<1|1);
push_up(o,R-L+1);
}

void Update(int L,int R,int o,int k,int val) {
if(L==R) {
Lnum[o]=Rnum[o]=val;
// Lsum[o]=Rsum[o]=Msum[o]=1;
return ;
}
int mid=(L+R)>>1;
if(k<=mid) Update(L,mid,o<<1,k,val);
else Update(mid+1,R,o<<1|1,k,val);
push_up(o,R-L+1);
}

int Query(int L,int R,int o,int ls,int rs) {
if(ls<=L&&rs>=R) {
return Msum[o];
}
int mid=(L+R)>>1;
int ans=0;
if(ls<=mid) ans=max(ans,Query(L,mid,o<<1,ls,rs));
if(rs>mid) ans=max(ans,Query(mid+1,R,o<<1|1,ls,rs));
if(Rnum[o<<1]<Lnum[o<<1|1])
ans=max(ans,min(mid-ls+1,Rsum[o<<1])+min(rs-mid,Lsum[o<<1|1]));
return ans;
}

int main() {
int cas,n,m,ls,rs;
scanf("%d",&cas);
while(cas--) {
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
build(1,n,1);
for(int i=1;i<=m;i++) {
scanf("%s %d %d",Q,&ls,&rs);
if(Q[0]=='Q') {
int res=Query(1,n,1,ls+1,rs+1);
printf("%d\n",res);
}
else {
Update(1,n,1,ls+1,rs);
}
}
}
return 0;85 }
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: