现在的位置: 首页 > 综合 > 正文

hdu 3308 线段树区间合并

2012年04月15日 ⁄ 综合 ⁄ 共 1523字 ⁄ 字号 评论关闭

单点更新就好了,简单题

一开始以为可以不连续,想来想去都觉得哪里不对劲,感觉无法解决,囧。。。。

#define max(a,b) ((a)>(b)?(a):(b)) 要注意加括号,因为没注意这个细节错了蛮久

线段树的三个域

lm[rt]:从左开始最长的连续递增子序列

rm[rt]:以右边界结尾的最长的。。。。

mx[rt]:管辖区间内最长的。。。。。

如果num[mid]<num[mid+1],可以对区间上的域进行合并

还没那个hotel

View Code

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 100010;
#define max(a,b) (a>b?a:b)
#define min(a,b) (a<b?a:b)
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
int lm[maxn<<2],rm[maxn<<2],mx[maxn<<2];
int num[maxn];
void pushup(int rt,int l,int r) {
lm[rt]=lm[rt<<1];
rm[rt]=rm[rt<<1|1];
mx[rt]=max(mx[rt<<1],mx[rt<<1|1]);
int mid=(l+r)>>1;
if(num[mid] < num[mid+1]) {
if(lm[rt]==mid-l+1) lm[rt]+=lm[rt<<1|1];
if(rm[rt]==r-mid) rm[rt]+=rm[rt<<1];
mx[rt]=max(mx[rt],rm[rt<<1]+lm[rt<<1|1]);
}
}
void build(int l,int r,int rt) {
if(l==r) {
lm[rt]=rm[rt]=mx[rt]=1;
return ;
}
int m=(l+r)>>1;
build(lson);
build(rson);
pushup(rt,l,r);
}
void update(int pos,int l,int r,int rt) {
if(l==r) return ;
int m=(l+r)>>1;
if(pos<=m) update(pos,lson);
else update(pos,rson);
pushup(rt,l,r);
}
int query(int L,int R,int l,int r,int rt) {
if(L<=l&&r<=R) return mx[rt];
int m=(l+r)>>1;
if(R<=m) return query(L,R,lson);
if(L>m) return query(L,R,rson);
int a=query(L,R,lson);
int b=query(L,R,rson);
int ans=a>b?a:b;
if(num[m]<num[m+1]) {
int tmp=min(rm[rt<<1],m-L+1)+min(lm[rt<<1|1],R-m);
ans=max(ans,tmp);
}
return ans;
}
int main() {
int n,m,i,j,t,a,b;
char op[5];
scanf("%d",&t);
while(t--) {
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++) scanf("%d",&num[i]);
build(1,n,1);
while(m--) {
scanf("%s%d%d",op,&a,&b);
if(op[0]=='U') {
a++;
num[a]=b;
update(a,1,n,1);
}
else {
a++;b++;
int ans=query(a,b,1,n,1);
printf("%d\n",ans);
}
}
}
}

抱歉!评论已关闭.