好题线段树区间合并(CDQ分治)——cf1316F
Posted zsben991126
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了好题线段树区间合并(CDQ分治)——cf1316F相关的知识,希望对你有一定的参考价值。
/* 离线读入所有值后离散化 题意要求的是,sum{ ai*2^(i-1)*aj*2^(n-j) } 分析这个式子,考虑进行分治 区间[l,r]的 sum{ ai*2^(i-l)*aj*2^(r-j) } 可以将式子分成 ai*2^(i-l) 和 aj*2^(r-j)两部分看, 线段树维护四个值,sum,pre,suf,size:分别表示这个 区间的答案, ai*2^(i-l)的和 aj*2^(r-j)的和 区间有效元素个数 那么当两个区间合并时 sum = suml*2^sizer + sumr*2^sizel + prel*sufr,对应i,j都从左区间里出,i,j都从右区间里出,i,j从左右区间出 pre = prel + prer*2^sizel,对应左区间的pre,右区间的pre*左区间的元素个数 suf = sufr + sufl*2^sizer size = sizel + sizer 初始值:sum=0,size=0,pre=0,suf=0 考虑位置i的值变为x 下降到叶子结点:size=1,pre=suf=x */ #include<bits/stdc++.h> using namespace std; #define ll long long #define mod 1000000007 #define N 600005 ll Pow(ll a,ll b){ ll res=1; while(b){ if(b%2)res=res*a%mod; b>>=1;a=a*a%mod; } return res; } ll P[N]; struct Node{ int id,x; }q[N<<1]; ll n,p[N],Q; #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 struct Seg{ ll sum,pre,suf,size; }s[N<<2]; Seg merge(Seg A,Seg B){ Seg res; res.sum=(A.sum*P[B.size]%mod+B.sum*P[A.size]%mod+A.pre*B.suf%mod)%mod; res.pre=(A.pre+B.pre*P[A.size]%mod)%mod; res.suf=(B.suf+A.suf*P[B.size]%mod)%mod; res.size=(A.size+B.size)%mod; return res; } void update(int pos,ll x,int l,int r,int rt){ if(l==r){ s[rt].sum=0; s[rt].pre=s[rt].suf=x; if(x!=0)s[rt].size=1; else s[rt].size=0; return; } int m=l+r>>1; if(pos<=m)update(pos,x,lson); else update(pos,x,rson); s[rt]=merge(s[rt<<1],s[rt<<1|1]); } int pos1[N],pos2[N],m; struct OP{ int id,x; }op[N<<1]; int cmp(OP a,OP b){return a.x<b.x;} int main(){ P[0]=1; for(int i=1;i<=300000;i++)P[i]=P[i-1]*2ll%mod; scanf("%lld",&n); for(int i=1;i<=n;i++){ scanf("%lld",&p[i]); op[i].id=i;op[i].x=p[i]; } scanf("%lld",&Q); for(int i=1;i<=Q;i++){ scanf("%lld%lld",&q[i].id,&q[i].x); op[i+n].id=i+n; op[i+n].x=q[i].x; } m=n+Q; sort(op+1,op+1+n+Q,cmp); for(int i=1;i<=n+Q;i++){ if(op[i].id<=n) pos1[op[i].id]=i; else pos2[op[i].id-n]=i; } memset(s,0,sizeof s); for(int i=1;i<=n;i++) update(pos1[i],p[i],1,m,1); ll base=Pow(P[n],mod-2); printf("%lld ",s[1].sum*base%mod); for(int i=1;i<=Q;i++){ update(pos1[q[i].id],0,1,m,1); update(pos2[i],q[i].x,1,m,1); cout<<s[1].sum*base%mod<<‘ ‘; pos1[q[i].id]=pos2[i]; } }
以上是关于好题线段树区间合并(CDQ分治)——cf1316F的主要内容,如果未能解决你的问题,请参考以下文章