2 条题解
-
1吴宇伦 (Arlen) LV 5 MOD @ 2021-01-28 16:55:43
#include<cstdio> #include<iostream> #define lson p<<1 #define rson p<<1|1 using namespace std; typedef long long ll; const int MAXN=100005; struct Node{ int l,r,lm,rm,ans; ll lv,rv; #define l(x) tre[x].l #define r(x) tre[x].r #define lm(x) tre[x].lm #define rm(x) tre[x].rm #define ans(x) tre[x].ans #define lv(x) tre[x].lv #define rv(x) tre[x].rv }tre[MAXN<<2]; int n,q,a[MAXN]; ll lz[MAXN<<2]; int cal(int num) { return (num+1)>>1; } void pushup(int p) { if(rv(lson)!=lv(rson)) { ans(p)=ans(lson)+ans(rson); ans(p)-=cal(rm(lson))+cal(lm(rson)); ans(p)+=cal(rm(lson)+lm(rson)+1); if(lm(lson)==r(lson)-l(lson)) lm(p)=lm(lson)+lm(rson)+1; else lm(p)=lm(lson); if(rm(rson)==r(rson)-l(rson)) rm(p)=rm(rson)+rm(lson)+1; else rm(p)=rm(rson); } else { ans(p)=ans(lson)+ans(rson); lm(p)=lm(lson); rm(p)=rm(rson); } lv(p)=lv(lson); rv(p)=rv(rson); } void pushdown(int p) { lv(lson)+=lz[p]; rv(lson)+=lz[p]; lv(rson)+=lz[p]; rv(rson)+=lz[p]; lz[lson]+=lz[p]; lz[rson]+=lz[p]; lz[p]=0; } void build_tree(int l,int r,int p) { l(p)=l,r(p)=r; if(l==r) { lv(p)=rv(p)=a[l]; return; } int mid=(l+r)>>1; build_tree(l,mid,lson); build_tree(mid+1,r,rson); pushup(p); } void updat(int l,int r,ll k,int p) { if(l(p)>r||r(p)<l)return; if(l(p)>=l&&r(p)<=r) { lz[p]+=k; lv(p)+=k; rv(p)+=k; return; } pushdown(p); updat(l,r,k,lson); updat(l,r,k,rson); pushup(p); } Node query(int l,int r,int p) { if(l(p)>=l&&r(p)<=r)return tre[p]; int mid=(l(p)+r(p))>>1; pushdown(p); if(r<=mid)return query(l,r,lson); if(l>mid)return query(l,r,rson); Node lf=query(l,r,lson),ri=query(l,r,rson),un; if(lf.rv!=ri.lv) { un.ans=lf.ans+ri.ans; un.ans-=cal(lf.rm)+cal(ri.lm); un.ans+=cal(lf.rm+ri.lm+1); if(lf.lm==lf.r-lf.l) un.lm=lf.lm+ri.lm+1; else un.lm=lf.lm; if(ri.rm==ri.r-ri.l) un.rm=ri.rm+lf.rm+1; else un.rm=ri.rm; } else { un.ans=lf.ans+ri.ans; un.lm=lf.lm; un.rm=ri.rm; } un.lv=lf.lv; un.rv=ri.rv; un.l=lf.l; un.r=ri.r; return un; } int main() { scanf("%d",&n); for(int i=1;i<=n;++i)scanf("%d",&a[i]); build_tree(1,n,1); scanf("%d",&q); for(int i=1;i<=q;++i) { int tp,s,t,h; scanf("%d",&tp); if(tp==1) { scanf("%d%d%d",&s,&t,&h); updat(s,t,h,1); } else { scanf("%d%d",&s,&t); Node fans=query(s,t,1); printf("%d\n",fans.ans); } } return 0; }
-
02021-01-30 13:36:28@
理解题意
这道题的模型是“ 给一段数列,询问最少去掉多少个数(形成断点)使剩下来连续的数相等”。
比如“1 2 2 2 3 4 4”,去掉一些数后变为“1()22()44”,当然也可以变为“()222()44”。寻找规律
设一段连续不相等的数有x个,如“1 2 3 2 1”,x=5。我们发现直接隔一个断掉一个就是答案。所以x/2就是最少断点数。 一段数列一定是由数个连续不相等的数和连续相等的数组成的。由于连续相等的数不需要断点,所以 答案就是将每一段连续不相等的数除以二相加(即x1/2+x2/2+……+xn/2);
解题
但是题目中还加上了区间修改的操作,所以可以用线段树来维护。
码风
下面所给的代码,左右节点标号分别用lson、rson进行了宏定义,
节点内储存的数据key全部用了 #define key(x) tre[x].key 这样的形式进行了宏定义存储
假设我们已经知道线段树两个节点的答案,合并两个节点时只需要考虑两个节点相邻的两个数是否相等,如果相等,则两个节点答案互不影响,直接相加;如果不相等,就要重新计算一下合并后新出现的一段连续不相等数的断点数。所以每个节点需要存储最左、最右数(用于合并节点时比较)、答案、最左连续不相等数的个数、最右连续不相等数的个数(用于合并时重新计算)。
合并
合并时只需要判断左右节点相邻数是否相等。
相等答案直接相加,左右最大连续数直接继承。ans(p)=ans(lson)+ans(rson); lm(p)=lm(lson); rm(p)=rm(rson);
不相等时复杂一些,答案需要重新计算一下相邻部分连续不相等数。
ans(p)=ans(lson)+ans(rson); ans(p)-=cal(rm(lson))+cal(lm(rson));//去掉原本连续不相等数的答案 ans(p)+=cal(rm(lson)+lm(rson));//加上重新计算出的答案 if(lm(lson)==r(lson)-l(lson)+1)//左节点全部连续不相等 lm(p)=lm(lson)+lm(rson); else lm(p)=lm(lson); if(rm(rson)==r(rson)-l(rson)+1)//右节点全部连续不相等 rm(p)=rm(rson)+rm(lson); else rm(p)=rm(rson);
询问
对于每次询问,递归下去直到找到完全包含的节点,并 将节点返回,将返回的节点依次合并(方法见“合并”一栏)。
下面是完整代码
#include<cstdio> #include<iostream> #define lson p<<1 #define rson p<<1|1 using namespace std; typedef long long ll; const int MAXN=100005; struct Node{ int l,r,lm,rm,ans; ll lv,rv; #define l(x) tre[x].l #define r(x) tre[x].r #define lm(x) tre[x].lm #define rm(x) tre[x].rm #define ans(x) tre[x].ans #define lv(x) tre[x].lv #define rv(x) tre[x].rv }tre[MAXN<<2]; int n,q,a[MAXN]; ll lz[MAXN<<2]; int cal(int num) { return num>>1; } void pushup(int p) { if(rv(lson)!=lv(rson))//两个节点相邻数不相等 { ans(p)=ans(lson)+ans(rson); ans(p)-=cal(rm(lson))+cal(lm(rson));//去掉原本连续不相等数的答案 ans(p)+=cal(rm(lson)+lm(rson));//加上重新计算出的答案 if(lm(lson)==r(lson)-l(lson)+1)//左节点全部连续不相等 lm(p)=lm(lson)+lm(rson); else lm(p)=lm(lson); if(rm(rson)==r(rson)-l(rson)+1)//右节点全部连续不相等 rm(p)=rm(rson)+rm(lson); else rm(p)=rm(rson); } else { ans(p)=ans(lson)+ans(rson); lm(p)=lm(lson); rm(p)=rm(rson); } lv(p)=lv(lson); rv(p)=rv(rson); } void pushdown(int p) { lv(lson)+=lz[p]; rv(lson)+=lz[p]; lv(rson)+=lz[p]; rv(rson)+=lz[p]; lz[lson]+=lz[p]; lz[rson]+=lz[p]; lz[p]=0; } void build_tree(int l,int r,int p) { l(p)=l,r(p)=r; if(l==r) { lm(p)=rm(p)=1; lv(p)=rv(p)=a[l]; return; } int mid=(l+r)>>1; build_tree(l,mid,lson); build_tree(mid+1,r,rson); pushup(p); } void updat(int l,int r,ll k,int p) { if(l(p)>r||r(p)<l)return; if(l(p)>=l&&r(p)<=r) { lz[p]+=k; lv(p)+=k; rv(p)+=k; return; } pushdown(p); updat(l,r,k,lson); updat(l,r,k,rson); pushup(p); } Node query(int l,int r,int p) { if(l(p)>=l&&r(p)<=r)return tre[p]; int mid=(l(p)+r(p))>>1; pushdown(p); if(r<=mid)return query(l,r,lson); if(l>mid)return query(l,r,rson); Node lf=query(l,r,lson),ri=query(l,r,rson),un; if(lf.rv!=ri.lv) { un.ans=lf.ans+ri.ans; un.ans-=cal(lf.rm)+cal(ri.lm); un.ans+=cal(lf.rm+ri.lm); if(lf.lm==lf.r-lf.l+1) un.lm=lf.lm+ri.lm; else un.lm=lf.lm; if(ri.rm==ri.r-ri.l+1) un.rm=ri.rm+lf.rm; else un.rm=ri.rm; } else { un.ans=lf.ans+ri.ans; un.lm=lf.lm; un.rm=ri.rm; } un.lv=lf.lv; un.rv=ri.rv; un.l=lf.l; un.r=ri.r; return un; } int main() { scanf("%d",&n); for(int i=1;i<=n;++i)scanf("%d",&a[i]); build_tree(1,n,1); scanf("%d",&q); for(int i=1;i<=q;++i) { int tp,s,t,h; scanf("%d",&tp); if(tp==1) { scanf("%d%d%d",&s,&t,&h); updat(s,t,h,1); } else { scanf("%d%d",&s,&t); Node fans=query(s,t,1); printf("%d\n",fans.ans); } } return 0; }
- 1