题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=1540
题意:是一条线上的点,D x是破坏这个点,Q x是表示查询以x所在的最长的连续的点的个数,R是恢复上一次破坏的点。
线段树功能:单点修改,区间求值。
分析: pre数组记录区间左端点开始的最大连续个数, suf数组记录区间右端点开始往左的最大的连续个数,sum数组表示该区间最大的连续点的个数。
sum[rt]最大值是左区间的最大值或右区间的最大值或左区间的suf+右区间的pre。
#pragma comment(linker,"/STACK:102400000,102400000") #include <cstdio> #include <cstring> #include <string> #include <cmath> #include <iostream> #include <algorithm> #include <queue> #include <cstdlib> #include <stack> #include <vector> #include <set> #include <map> #define LL long long #define mod 1000000007 #define inf 0x3f3f3f3f #define N 50010 #define FILL(a,b) (memset(a,b,sizeof(a))) #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 using namespace std; int sum[N<<2],pre[N<<2],suf[N<<2]; int a[N]; void Pushup(int rt,int len) { pre[rt]=pre[rt<<1]; suf[rt]=suf[rt<<1|1]; if(pre[rt<<1]==(len-(len>>1)))pre[rt]=pre[rt<<1]+pre[rt<<1|1]; if(suf[rt<<1|1]==(len>>1))suf[rt]=suf[rt<<1]+suf[rt<<1|1]; sum[rt]=max(suf[1<<1]+pre[1<<1|1],max(sum[rt<<1],sum[rt<<1|1])); } void build(int l,int r,int rt) { if(l==r) { sum[rt]=pre[rt]=suf[rt]=1; return; } int m=(l+r)>>1; build(lson); build(rson); Pushup(rt,r-l+1); } void update(int pos,int c,int l,int r,int rt) { if(l==r) { sum[rt]=suf[rt]=pre[rt]=c; return; } int m=(l+r)>>1; if(pos<=m)update(pos,c,lson); else update(pos,c,rson); Pushup(rt,r-l+1); } int query(int pos,int l,int r,int rt) { if(l==r) return sum[rt]; int m=(l+r)>>1; if(pos<=m) { if(pos+suf[rt<<1]>m)return suf[rt<<1]+pre[rt<<1|1]; else return query(pos,lson); } else { if(m+pre[rt<<1|1]>=pos)return pre[rt<<1|1]+suf[rt<<1]; else return query(pos,rson); } } int main() { int n,m,x,tot; char op[10]; while(scanf("%d%d",&n,&m)>0) { build(1,n,1); tot=0; while(m--) { scanf("%s",op); if(op[0]==‘Q‘) { scanf("%d",&x); printf("%d\n",query(x,1,n,1)); } else if(op[0]==‘D‘) { scanf("%d",&x); a[++tot]=x; update(x,0,1,n,1); } else { x=a[tot--]; update(x,1,1,n,1); } } } }
原文:http://www.cnblogs.com/lienus/p/4240388.html