前面讲完了主席树,那现在就来考虑可修改的主席树。
如果直接修改主席树,我们就需要用 O(nlog2n) 的时间来逐个逐个修改,那么我们可否用更小的时间来修改呢?
我们之所以前面的主席树的修改时间如此大是因为每个 rooti 的主席树包含了 root1,root2...rooti−1 的主席树。
那么可不可以用另外一种神奇的东西来使得 rooti 只用管理少数几个 root ,这样的东西似乎似曾相识。
线段树!!!
rooti 的主席树包含了 rooti×2 和 rooti×2+1 的主席树。
我是用树状数组来实现的,每次的修改就沿着 x 向其父亲走,每到一个 root 修改一次,而询问操作就把所有合起来管理询问的区间的 root 取出来,递归求第 k 大时就所有 root 同时跳到其儿子或父亲,然后就可以完美解决了,空间复杂度 O(nlog2n) ,时间复杂度 O(nlog2n)
下面附一下代码():
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define MAXN 100010
typedef double LL;
using namespace std;
struct node{
LL v1,v2,v3;
int v4;
int l,r,tot;
}tree[4000010];
int root[1010],tot,h[MAXN],f[11],k,n,m;
LL ans;
int get(){
char ch;
while (ch=getchar(),(ch<'0'||ch>'9')&& ch!='-');
char c=ch;
int s;
if (c!='-')s=c-48;else s=0;
while (ch=getchar(),ch>='0'&&ch<='9')s=s*10+ch-48;
return c=='-'?-s:s;
}
void inse(int l,int r,int &t,int x,int y,int tim){
if (!t)t=++tot;
tree[t].tot+=tim;
if (l==r){
if (x>y){
tree[t].v1+=LL(1)/(x-y)*tim;
tree[t].v2+=LL(y)/(x-y)*tim;
tree[t].v3+=LL(y*y)/(x-y)*tim;
}
tree[t].v4+=(x+y)*tim;
return;
}
int mid=(l+r)/2;
if (x<=mid)inse(l,mid,tree[t].l,x,y,tim);
else inse(mid+1,r,tree[t].r,x,y,tim);
int ls=tree[t].l,rs=tree[t].r;
tree[t].v1=tree[ls].v1+tree[rs].v1;
tree[t].v2=tree[ls].v2+tree[rs].v2;
tree[t].v3=tree[ls].v3+tree[rs].v3;
tree[t].v4=tree[ls].v4+tree[rs].v4;
}
void add(int x,int y,int tim){
int y1=y;
while (y<1001){
inse(1,1001,root[y],x,y1,tim);
y=y+(y& -y);
}
}
void cc(int i,int x){
if (iif (h[i]>h[i+1])add(h[i],h[i+1],-1);
else add(h[i+1],h[i],-1);
if (x1])add(h[i+1],x,1);
else add(x,h[i+1],1);
}
if (i>1){
if (h[i-1]>h[i])add(h[i-1],h[i],-1);
else add(h[i],h[i-1],-1);
if (x1])add(h[i-1],x,1);
else add(x,h[i-1],1);
}
h[i]=x;
}
void getl(){
fo(i,1,k)f[i]=tree[f[i]].l;
}
void getr(){
fo(i,1,k)f[i]=tree[f[i]].r;
}
void getanswer(int l,int r,int x){
if (l>x){
fo(i,1,k)ans=ans+0.5*(tree[f[i]].v1*x*x-tree[f[i]].v2*x*2+tree[f[i]].v3);
return;
}
if (r<=x){
fo(i,1,k)ans=ans+tree[f[i]].tot*x-0.5*tree[f[i]].v4;
return;
}
int tt[11];
fo(i,1,k)tt[i]=f[i];
getl();
int mid=(l+r)/2;
getanswer(l,mid,x);
fo(i,1,k)f[i]=tt[i];
getr();
getanswer(mid+1,r,x);
}
void getans(int x){
k=0;
int y=x;
while (y){
f[++k]=root[y];
y=y-(y & -y);
}
ans=0;
getanswer(1,1001,x);
}
int main(){
n=get();m=get();
fo(i,1,n)h[i]=get()+1;
fo(i,1,n-1)
if (h[i]1])add(h[i+1],h[i],1);
else add(h[i],h[i+1],1);
fo(i,1,m){
char ch;
while (ch=getchar(),ch!='Q'&&ch!='U');
if (ch=='Q'){
int x=get()+1;
getans(x);
printf("%.3lf\n",ans);
}
else{
int x=get()+1,y=get()+1;
cc(x,y);
}
}
}