题意:给你一个数组,有两种查询:1 pos x就是把pos地方的值修改成x,2 l r x y,代表区间在l到r中,权值范围在x到y的区间的个数。这个区间要尽可能的长,且区间中的值都相等。
思路代码原链接:原文链接
最后一个样例,1到6中的合法区间是(1,2)、(3,3)、(4,4)、(6,6)。
首先假设没有1操作,那么我们可以用主席树写,因为主席树保存了前缀信息,那么我们可以对每一个pos建一棵权值线段树,然后,如果这个位置的权值与前面的权值相同就continue,否则就加入。但是如果有修改,因为主席树保存了前缀信息,所以说,这颗线段树后面的所有的线段树的值都需要修改,很明显这样时间复杂度过不去。
所以动态修改,用动态开点线段树套树状数组,思路就是,之前是对每一个位置建树,但是现在是在一个树状数组中建树,这写树没有关联,独立存在,那么我们要修改一个节点的值,我们就得修改以这个节点为起点的树状数组上面的所有值。需要注意的一点是,对于修改的那个节点,需要考虑他的前面那个节点的值后面那个节点的值与修改前的值和修改后的值的相同性。
先主席树不带修改的代码:
#include
using namespace std; const int maxn=2e5+100; const int N=2e5+10; int tr[maxn*4],ls[maxn*4],rs[maxn*4],rt[maxn],a[maxn],cnt; #define mid (l+r)/2 void up(int &o,int pre,int l,int r,int p) { o=++cnt; ls[o]=ls[pre]; rs[o]=rs[pre]; tr[o] = tr[pre] + 1; if(l==r)return ; if(p<=mid)up(ls[o],ls[pre],l,mid,p); else up(rs[o],rs[pre],mid+1,r,p); tr[o]=tr[ls[o]]+tr[rs[o]]; } int qu(int o,int l,int r,int L,int R) { if(l>=L&&r<=R)return tr[o]; int ans=0; if(L<=mid)ans+=qu(ls[o],l,mid,L,R); if(R>mid)ans+=qu(rs[o],mid+1,r,L,R); return ans; } int main() { int n,m; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%d",a+i); rt[i]=rt[i-1]; if(a[i]==a[i-1])continue; up(rt[i],rt[i],1,N,a[i]); } while(m--) { int ql,qr,x,y; scanf("%d%d%d%d",&ql,&qr,&x,&y); int ans=qu(rt[qr],1,n,x,y)-qu(rt[ql-1],1,n,x,y); cout< 然后是带修改的ac代码:
用了快读就不能scanf了。
#include
#define low(x) x&-x using namespace std; const int maxn=2e5+100; int n,tot,cnt,rt[maxn],a[maxn],V[25]; int sum[maxn*210],ls[maxn*210],rs[maxn*210]; #define mid (l+r)/2 void up(int l,int r,int p,int v) { for(int i=1;i<=tot;i++) { sum[V[i]]+=v; } if(l==r)return ; if(p<=mid) { for(int i=1;i<=tot;i++) { if(!ls[V[i]])ls[V[i]]=++cnt; V[i]=ls[V[i]]; } up(l,mid,p,v); } else { for(int i=1;i<=tot;i++) { if(!rs[V[i]])rs[V[i]]=++cnt; V[i]=rs[V[i]]; } up(mid+1,r,p,v); } } void modify(int x,int p,int v) { tot=0; for(;x<=n;x+=low(x)) { V[++tot]=rt[x]; } up(1,n,p,v); } int qu(int l,int r,int L,int R) { if(l>=L&&r<=R) { int an=0; for(int i=1;i<=tot;i++) { an+=sum[V[i]]; } return an; } int ans=0; int V1[21]; if(L<=mid) { for(int i=1;i<=tot;i++) { V1[i]=V[i]; V[i]=ls[V[i]]; } ans+=qu(l,mid,L,R); for(int i=1;i<=tot;i++) { V[i]=V1[i]; } } if(mid 0;x-=low(x)) { V[++tot]=rt[x]; } return qu(1,n,ql,qr); } //快读 #define reads(n) FastIO::read(n) namespace FastIO { const int SIZE = 1 << 16; char buf[SIZE], obuf[SIZE], str[60]; int bi = SIZE, bn = SIZE, opt; int read(char *s) { while (bn) { for (; bi < bn && buf[bi] <= ' '; bi++); if (bi < bn) break; bn = fread(buf, 1, SIZE, stdin); bi = 0; } int sn = 0; while (bn) { for (; bi < bn && buf[bi] > ' '; bi++) s[sn++] = buf[bi]; if (bi < bn) break; bn = fread(buf, 1, SIZE, stdin); bi = 0; } s[sn] = 0; return sn; } bool read(int& x) { int n = read(str), bf; if (!n) return 0; int i = 0; if (str[i] == '-') bf = -1, i++; else bf = 1; for (x = 0; i < n; i++) x = x * 10 + str[i] - '0'; if (bf < 0) x = -x; return 1; } }; int main() { int m,ql,qr,opt,x,y; reads(n); reads(m); for(int i=1;i<=n;i++) { rt[i]=++cnt; } for(int i=1;i<=n;i++) { reads(a[i]); if(a[i]!=a[i-1])modify(i,a[i],1); } while(m--) { reads(opt); reads(ql); reads(qr); if(opt==1) { if(a[ql]==qr)continue; if(a[ql]!=a[ql-1]) { modify(ql,a[ql],-1); if(a[ql-1]!=qr)modify(ql,qr,1); } else { if(a[ql-1]!=qr)modify(ql,qr,1); } if(a[ql]==a[ql+1]) { modify(ql+1,a[ql+1],1); } else if(a[ql+1]==qr) { modify(ql+1,a[ql+1],-1); } a[ql]=qr; } else if(opt==2) { reads(x); reads(y); int ans=_qu(qr,x,y)-_qu(ql-1,x,y); if(a[ql]==a[ql-1]&&a[ql]>=x&&a[ql]<=y) ans++; printf("%d\n",ans); } } }