CF757G Can Bash Save the Day?
阿新 • • 發佈:2022-03-04
https://www.luogu.com.cn/problem/CF757G
可持久化點分樹
首先一個暴力的想法就是點分樹上每個點開一個線段樹,下標是那個排列 \(p\) 的下標,維護個數和距離和
但發現這樣空間就變成 \(O(n\log ^2 n)\) 了,而且有修改,不能像 開店 那個題那樣簡化成 vector
上二分
卡空間的話把線段樹改成平衡樹,常數變大,但感覺 5s 還是可過
來個不那麼暴力的做法
由於區間詢問可以差分,考慮給每個字首維護一個點分樹
修改的時候,就從點分樹的根開始,每次把上一個字首這個位置的節點複製過來,把個數、距離和修改掉,兒子們等資訊不變
同樣有點分樹常見的那個容斥
然而發現每個點最多會有 \(O(n)\)
這樣建完點分樹上一個點最多會有 \(3\) 個兒子
於是時空都是 \(O(n\log n)\) 了
轉二叉樹的過程見程式碼
#define N 400006 #define M 800006 #define LOG_N 20 int lg2[N*2]; struct GraphT{ int fir[N],nex[M],to[M],w[M],tot; inline void add(int u,int v,int c,int flag=1){ to[++tot]=v;nex[tot]=fir[u];fir[u]=tot;w[tot]=c; if(flag) add(v,u,c,0); } inline void clear(){std::memset(fir,0,sizeof fir);tot=0;} int st[LOG_N+2][N*2],id[N*2]; int deep[N],dfscnt,dfn[N]; long long sum[N]; void dfs(int u,int fa=0){ deep[u]=deep[fa]+1;dfn[u]=++dfscnt;id[dfscnt]=u; for(int v,i=fir[u];i;i=nex[i]){ v=to[i]; if(v==fa) continue; sum[v]=sum[u]+w[i]; dfs(v,u);id[++dfscnt]=u; } } inline void initLca(){ dfs(1);st[0][1]=id[1]; for(int i=2;i<=dfscnt;i++) lg2[i]=lg2[i>>1]+1,st[0][i]=id[i]; for(int j=1;j<=LOG_N;j++)for(int i=1;i+(1<<j)<=dfscnt;i++) st[j][i]=deep[st[j-1][i]]<deep[st[j-1][i+(1<<(j-1))]]?st[j-1][i]:st[j-1][i+(1<<(j-1))]; } inline int getLca(int u,int v)const{ if(dfn[u]>dfn[v]) lib::swap(u,v); u=dfn[u];v=dfn[v]; int o=lg2[v-u+1]; return deep[st[o][u]]<deep[st[o][v-(1<<o)+1]]?st[o][u]:st[o][v-(1<<o)+1]; } inline long long getDis(const int &u,const int &v)const{return sum[u]+sum[v]-(sum[getLca(u,v)]<<1);} }G,T;//T rebuild -> G int n; int root,size[N],maxson[N],vis[N]; void findRoot(int u,int fa=0){ size[u]=1;maxson[u]=0; for(int v,i=G.fir[u];i;i=G.nex[i]){ v=G.to[i]; if(v==fa||vis[v]) continue; findRoot(v,u);size[u]+=size[v]; lib::chkMax(maxson[u],size[v]); } lib::chkMax(maxson[u],size[0]-size[u]); if(maxson[u]<maxson[root]) root=u; } struct Node{ Node *son[3]; int id,size; long long sum,sumfa; }addr[N*30],*totAddr=addr,*rt[N];//rt: root int newFa[N],deep[N]; std::vector<int>sonId[N]; inline void New(Node *&x){x=totAddr++;} void divide(int u,Node *now,int tot){ vis[u]=1;now->id=u; Node *nex; for(int v,i=G.fir[u];i;i=G.nex[i]){ v=G.to[i]; if(vis[v]) continue; root=0;size[0]=size[v]>size[u]?(tot-size[u]):size[v]; findRoot(v);newFa[root]=u;deep[root]=deep[u]+1; for(int j=0;j<deep[u];j++) sonId[root].push_back(sonId[u][j]); New(nex); if(!now->son[0]) now->son[0]=nex,sonId[root].push_back(0); else if(!now->son[1]) now->son[1]=nex,sonId[root].push_back(1); else now->son[2]=nex,sonId[root].push_back(2); divide(root,nex,size[v]); } } int deg[N],totNode; void rebuild(int u,int fa=0){ for(int last=0,tmp=0,v,i=T.fir[u];i;i=T.nex[i]){ v=T.to[i]; if(v==fa) continue; if(++tmp==1) G.add(u,v,T.w[i]),last=u; else if(tmp==deg[u]-(u!=1)) G.add(last,v,T.w[i]); else G.add(last,++totNode,0),G.add(totNode,v,T.w[i]),last=totNode; } for(int i=T.fir[u];i;i=T.nex[i])if(T.to[i]^fa) rebuild(T.to[i],u); } inline void build(){ totNode=n;rebuild(1); root=0;maxson[0]=_INT_INF;size[0]=n; findRoot(1); New(rt[0]);divide(root,rt[0],size[1]); } inline void update(Node *last,Node *&tree,int u,int k){ New(tree); Node *now=tree; for(int id=0;;){ *now=*last;id=now->id; now->size+=k;now->sum+=k*G.getDis(u,id); if(newFa[id]) now->sumfa+=k*G.getDis(u,newFa[id]); if(id==u) return; last=last->son[sonId[u][deep[id]]]; New(now->son[sonId[u][deep[id]]]);now=now->son[sonId[u][deep[id]]]; } } inline long long ask(Node *l,Node *r,int u){ long long ans=0; Node *nexL,*nexR; for(int i=0;i<deep[u];i++,l=nexL,r=nexR){ nexL=l->son[sonId[u][i]];nexR=r->son[sonId[u][i]]; ans+=(r->size-nexR->size-(l->size-nexL->size))*G.getDis(u,r->id)+(r->sum-nexR->sumfa-(l->sum-nexL->sumfa)); } return ans+r->sum-l->sum; } int main(){ n=read();int q=read(); static int p[N]; for(int i=1;i<=n;i++) p[i]=read(); for(int u,v,i=1;i<n;i++) u=read(),v=read(),T.add(u,v,read()),deg[u]++,deg[v]++; build(); G.initLca(); for(int i=1;i<=n;i++) update(rt[i-1],rt[i],p[i],1); long long lastans=0; #define MOD 1073741824 while(q--){ int op=read(); if(op==1){ int l=read()^lastans,r=read()^lastans; writeEN(lastans=ask(rt[l-1],rt[r],read()^lastans));lastans%=MOD; } else{ int u=read()^lastans; lib::swap(p[u],p[u+1]);update(rt[u-1],rt[u],p[u],1); } } return RET; }