HLG 1524 最大
题意: 给一列数对应两种操作:
1 a b v, 把[a, b] 的值改为v,即A[a] = A[a+1] = ... = A[b] = v。
2 a b, 查询[a, b] 之间的相同数的连续和最大值。
分析:线段树,区间合并 + 成段更新 ...
int lva[maxn<<4]; // 区间最左面的值
int lnu[maxn<<4]; // 区间最左面的数的个数
int rva[maxn<<4]; // 区间最右面的值
int rnu[maxn<<4]; // 区间最右面的数的个数
int mva[maxn<<4]; // 区间最大连续值
int add[maxn<<4]; // 延迟标记
int lnu[maxn<<4]; // 区间最左面的数的个数
int rva[maxn<<4]; // 区间最右面的值
int rnu[maxn<<4]; // 区间最右面的数的个数
int mva[maxn<<4]; // 区间最大连续值
int add[maxn<<4]; // 延迟标记
区间合并:
当左儿子区间相同数字的长度达到区间长度且lva[lson]==lva[rson]时, 将左儿子和右儿子的 lnu合并
当右儿子区间相同数字的长度达到区间长度且rva[rson]==rva[lson]时,将左儿子和右儿子的 rnu合并
PS: 由于延迟标记 add[i] 在开始时默认add[i]为正值的时候才进行延迟覆盖, 而题目中 更新的 V 值可以为 0,这就意味着add[i]=0 的时候也要进行延迟更新,
为此debug了两个点,谨记...延迟标记要默认为达不到的值,这题只要默认为 -1 即可。
#include<stdio.h> #include<string.h> #define clr(x)memset(x,0,sizeof(x)) #define maxn 100005 int max(int a,int b) { return a>b?a:b;} int min(int a,int b) { return a<b?a:b;} int lva[maxn<<4]; // 最左面的值 int lnu[maxn<<4]; // 最左面的数的个数 int rva[maxn<<4]; // 最右面的值 int rnu[maxn<<4]; // 最右面的数的个数 int mva[maxn<<4]; // 区间最大连续值 int add[maxn<<4]; // 延迟标记 int v[maxn]; void creat(int l,int r,int rt) { add[rt]=-1; if(l==r) { lva[rt]=rva[rt]=v[l]; lnu[rt]=rnu[rt]=1; mva[rt]=v[l]; return; } int m=(l+r)>>1; creat(l,m,rt<<1); creat(m+1,r,rt<<1|1); lva[rt]=lva[rt<<1]; lnu[rt]=lnu[rt<<1]; rva[rt]=rva[rt<<1|1]; rnu[rt]=rnu[rt<<1|1]; if(lva[rt<<1]==lva[rt<<1|1]&&lnu[rt<<1]==(m-l+1)) lnu[rt]+=lnu[rt<<1|1]; if(rva[rt<<1]==rva[rt<<1|1]&&rnu[rt<<1|1]==r-m) rnu[rt]+=rnu[rt<<1]; mva[rt]=max(mva[rt<<1],mva[rt<<1|1]); if(rva[rt<<1]==lva[rt<<1|1]) mva[rt]=max(mva[rt],rva[rt<<1]*rnu[rt<<1]+lva[rt<<1|1]*lnu[rt<<1|1]); } void update(int L,int R,int c,int l,int r,int rt) { if(L<=l&&r<=R) { add[rt]=c; lva[rt]=rva[rt]=c; lnu[rt]=rnu[rt]=r-l+1; mva[rt]=c*(r-l+1); return; } int m=(l+r)>>1; if(add[rt]!=-1) { add[rt<<1]=add[rt<<1|1]=add[rt]; lva[rt<<1]=rva[rt<<1]=lva[rt<<1|1]=rva[rt<<1|1]=add[rt]; lnu[rt<<1]=rnu[rt<<1]=m-l+1; lnu[rt<<1|1]=rnu[rt<<1|1]=r-m; mva[rt<<1]=(m-l+1)*add[rt]; mva[rt<<1|1]=(r-m)*add[rt]; add[rt]=-1; } if(L<=m) update(L,R,c,l,m,rt<<1); if(R>m) update(L,R,c,m+1,r,rt<<1|1); lva[rt]=lva[rt<<1]; lnu[rt]=lnu[rt<<1]; rva[rt]=rva[rt<<1|1]; rnu[rt]=rnu[rt<<1|1]; if(lva[rt<<1]==lva[rt<<1|1]&&lnu[rt<<1]==(m-l+1)) lnu[rt]+=lnu[rt<<1|1]; if(rva[rt<<1]==rva[rt<<1|1]&&rnu[rt<<1|1]==r-m) rnu[rt]+=rnu[rt<<1]; mva[rt]=max(mva[rt<<1],mva[rt<<1|1]); if(rva[rt<<1]==lva[rt<<1|1]) mva[rt]=max(mva[rt],rva[rt<<1]*rnu[rt<<1]+lva[rt<<1|1]*lnu[rt<<1|1]); } int query(int L,int R,int l,int r,int rt) { if(L<=l&&r<=R) return mva[rt]; int m=(l+r)>>1; if(add[rt]!=-1) { add[rt<<1]=add[rt<<1|1]=add[rt]; lva[rt<<1]=rva[rt<<1]=lva[rt<<1|1]=rva[rt<<1|1]=add[rt]; lnu[rt<<1]=rnu[rt<<1]=m-l+1; lnu[rt<<1|1]=rnu[rt<<1|1]=r-m; mva[rt<<1]=(m-l+1)*add[rt]; mva[rt<<1|1]=(r-m)*add[rt]; add[rt]=-1; } if(R<=m) return query(L,R,l,m,rt<<1); else if(L>m) return query(L,R,m+1,r,rt<<1|1); else { int res=0; if(rva[rt<<1]==lva[rt<<1|1]) res=(min(rnu[rt<<1],m-L+1)+min(lnu[rt<<1|1],R-m))*rva[rt<<1]; return max(res,max(query(L,m,l,m,rt<<1),query(m+1,R,m+1,r,rt<<1|1))); } } int re[100005]; int main() { int i,n,a,b,c,m,op,ca=1,top=0; while(scanf("%d",&n)!=EOF) { for(i=1;i<=n;i++) scanf("%d",&v[i]); creat(1,n,1); scanf("%d",&m); int tot=0; printf("Case %d:\n",ca++); while(m--) { scanf("%d",&op); if(op==1) { scanf("%d%d%d",&a,&b,&c); update(a,b,c,1,n,1); } else { scanf("%d%d",&a,&b); printf("%d\n",query(a,b,1,n,1)); } } } return 0; }