P10516 数据结构 题解
给一个不带
分析
用
首先易知
换句话说我们可以用
问题在于怎样找到需要进行的操作,以及如何进行操作。
实现
我们审视一下
修改所有下标在
也就是说这是一个二维的限制。
直接分块的话光维护第一维限制就需要在
因此考虑在分块的基础上再次分块。
首先,将整个序列分为
然后,相邻的
这样,我们就将
这样,维护第一维就只需要处理好
维护整块内值域用类似的方法,对值域分三次块,分别是
这样我们查找整块内所有乘积在
最终时间复杂度
然而空间复杂度是
然而可以离线下来,每次只维护序列上一个大块,空间复杂度
代码:
#include <cstdio>
inline int rd(){
int x=0;
char c=getchar();
while(c<'0'||c>'9')c=getchar();
while(c>='0'&&c<='9')x=x*10+(c^48),c=getchar();
return x;
}
const int mx=100000,blen=5000,slen=500,klen=18;
const int klen_2=klen*klen,klen_3=klen*klen*klen;
int n,m,a[100010],b[100010],l[100010],r[100010],k[100010],t[100010];
struct node{
int pre,nxt;
inline void init(const int at){pre=nxt=at;}
}dt[5600000];
int tot,que[100010],sz;
struct line{
node *l;
inline void init(const int len){
l=dt+tot,tot+=len;
for(int i=1;i<=len;++i)l[i].init(i);
}
inline void link(const int u,const int v){
l[u].nxt=v,l[v].pre=u;
}
inline void add(const int u,const int to){
link(u,l[to+n+1].nxt),link(to+n+1,u);
}
inline void dlt(const int p){
l[l[p].nxt].pre=l[p].pre;
l[l[p].pre].nxt=l[p].nxt;
l[p].pre=l[p].nxt=p;
}
inline void pick(int plc)const{
plc+=n+1;
for(int u=l[plc].nxt;u!=plc;u=l[u].nxt)
que[++sz]=u;
}
};
typedef long long ll;
struct block{
line s[4];
ll sum;
inline void init(){
sum=0;
s[0].init((mx+1)<<1);
s[1].init(mx+1+klen_3);
s[2].init(mx+1+klen_2);
s[3].init(mx+1+klen);
}
inline void add(const int p,const ll to){
sum+=a[p]+b[p];
if(to>mx)return;
s[0].add(p,to);
if(to){
s[1].add(p,(to+klen-1)/klen);
s[2].add(p,(to+klen_2-1)/klen_2);
s[3].add(p,(to+klen_3-1)/klen_3);
}
}
inline void dlt(const int p){
sum-=a[p]+b[p];
s[0].dlt(p),s[1].dlt(p),s[2].dlt(p),s[3].dlt(p);
}
inline void sele(int k)const{
s[0].pick(0);
int nw=klen_3;
for(int i=1;nw<=k;nw+=klen_3,++i)s[3].pick(i);
nw+=klen_2-klen_3;
for(int i=nw/klen_2;nw<=k;nw+=klen_2,++i)s[2].pick(i);
nw+=klen-klen_2;
for(int i=nw/klen;nw<=k;nw+=klen,++i)s[1].pick(i);
for(nw+=1-klen;nw<=k;++nw)s[0].pick(nw);
}
}blk[11];
ll ans[100010];
inline void add(const int p){
ll v=(ll)a[p]*b[p];
blk[0].add(p,v);
blk[((p-1)%blen)/slen+1].add(p,v);
}
inline void dlt(const int p){
blk[0].dlt(p);
blk[((p-1)%blen)/slen+1].dlt(p);
}
inline void chg(const int p,const int x,const int y){
dlt(p),a[p]=x,b[p]=y,add(p);
}
inline void adv(const int p,const int v){chg(p,a[p]+v,b[p]+v);}
inline void sol(const int at){
const int vt=t[at];
if(!vt)return;
blk[0].sele(k[at]);
for(int i=1;i<=sz;++i)
adv(que[i],vt);
sz=0;
}
inline bool chkq(const int p){return r[p] && k[p]==0 && t[p]==0;}
inline void pros(const int p,const int at,const int tp){
if(tp){ans[at]+=a[p]+b[p];return;}
ll v=(ll)a[p]*b[p];
if(v<=k[at])adv(p,t[at]);
}
inline void part(const int l,const int r,const int at){
if(t[at]==0 && k[at])return;
int tl=(l-1)%blen/slen+1,tr=(r-1)%blen/slen+1,bg=l-l%blen,tp=chkq(at);
if(tl==tr){
for(int i=l;i<=r;++i)pros(i,at,tp);
return;
}
int el=bg+tl*slen,br=bg+(tr-1)*slen+1;
for(int i=l;i<=el;++i)pros(i,at,tp);
for(int i=br;i<=r;++i)pros(i,at,tp);
for(int i=tl+1;i<tr;++i){
if(tp)ans[at]+=blk[i].sum;
else blk[i].sele(k[at]);
}
if(tp)return;
for(int i=1;i<=sz;++i)
adv(que[i],t[at]);
sz=0;
}
inline void file(){
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
}
int main(){
// file();
n=rd(),m=rd();
for(int i=1;i<=n;++i)a[i]=rd();
for(int i=1;i<=n;++i)b[i]=rd();
for(int i=1,tp;i<=m;++i){
tp=rd();
if(tp==2)l[i]=rd(),k[i]=rd(),t[i]=rd();
else if(tp==3)l[i]=rd(),r[i]=rd();
else{
l[i]=rd(),r[i]=rd(),k[i]=rd(),t[i]=rd();
if(chkq(i))k[i]=1;
}
}
for(int bg=1,ed;bg<=n;bg+=blen){
ed=(bg+blen>n?n:bg+blen-1);
tot=0;
blk[0].init();
for(int kb=bg,ke,at=1;kb<=ed;kb+=slen,++at){
ke=(kb+slen>ed?ed:kb+slen-1);
blk[at].init();
for(int i=kb;i<=ke;++i)add(i);
}
for(int i=1;i<=m;++i){
if(!r[i]){
const int p=l[i];
if(p<bg || p>ed)continue;
chg(p,k[i],t[i]);
}
else{
if(l[i]>ed || r[i]<bg)continue;
if(l[i]<=bg && r[i]>=ed){
chkq(i)?ans[i]+=blk[0].sum:(sol(i),0);
continue;
}
if(l[i]<=bg){
part(bg,r[i],i);
continue;
}
if(r[i]>=ed){
part(l[i],ed,i);
continue;
}
part(l[i],r[i],i);
}
}
}
for(int i=1;i<=m;++i)
if(chkq(i))printf("%lld\n",ans[i]);
return 0;
}
然而时间也有