【题目】
CF
一棵
n
n
n个点的树和一个排列
p
i
p_i
pi,边有边权,支持两种操作:
- l r x l\ r\ x l r x,询问 ∑ i = l r d i s ( p i , x ) \sum\limits _{i=l}^{r} dis(p_i,x) i=l∑rdis(pi,x)
- x x x,交换 p x , p x + 1 p_x,p_{x+1} px,px+1
n , q ≤ 2 × 1 0 5 n,q\leq 2\times 10^5 n,q≤2×105,强制在线
【解题思路】
首先考虑没有修改怎么做。
这就是一个经典的动态点分治题(HNOI2015开店),我们将每个分治中心内存的信息按排列排序,那么每次询问就是一个前缀的差分。
现在有修改,观察到修改会影响到点分树一条链上的信息,我们可以 YY \text{YY} YY一个可持久化点分树出来:即对于每一个前缀维护一棵点分树。
于是对于第二种操作,我们只需要修改第 x x x棵点分树的信息即可。
但是点分树的可持久化有一个很不好的性质,我们可持久一个点的时候,需要保存这个点所有儿子的信息,显然这个可能是 O ( n ) O(n) O(n)级别的。怎么办?重构呗!我们直接按边分治重构树的方法,将原树重构成一棵二叉树即可。
这里注意的是点分树仍有可能有三个儿子,于是我们可能需要 O ( 1 ) LCA O(1)\text{LCA} O(1)LCA之类的东西了。
感觉不太可能把点分树重构了吧?
这样时空复杂度是 O ( n log n ) O(n\log n) O(nlogn)的。
【参考代码】
#include<bits/stdc++.h>
#define pb push_back
using namespace std;
typedef long long ll;
const int N=4e5+10,msk=(1<<30)-1;
int n,m,cnt;
namespace IO
{
int read()
{
int ret=0;char c=getchar();
while(!isdigit(c)) c=getchar();
while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
return ret;
}
void write(ll x){if(x>9)write(x/10);putchar(x%10^48);}
void writeln(ll x){write(x);putchar('\n');}
}
using namespace IO;
namespace Graph
{
int dtsz,ind,sum,root;
int mx[N],siz[N];
int du[N],dp[N],vis[N],pos[N],rt[N],Log[N<<1],fc[22];
ll mi[20][N<<1],dis[N];
vector<int>st[N];
struct Tway
{
int v,w,nex;
Tway(int _v=0,int _w=0,int _nex=0):v(_v),w(_w),nex(_nex){}
};
struct Tree
{
Tway e[N<<1];int tot,head[N];
void add(int u,int v,int w)
{
e[++tot]=Tway(v,w,head[u]);head[u]=tot;
e[++tot]=Tway(u,w,head[v]);head[v]=tot;
}
}T1,T2;
struct DT
{
ll s1,s2;
int ch[3],sz,id;
}tr[N*30];
void dfs1(int x,int f)
{
int tmp=0,las=0;
for(int i=T1.head[x];i;i=T1.e[i].nex)
{
int v=T1.e[i].v,w=T1.e[i].w;
if(v==f) continue; ++tmp;
if(tmp==1) T2.add(x,v,w),las=x;
else if(tmp==du[x]-(x!=1)) T2.add(las,v,w);
else ++cnt,T2.add(las,cnt,0),T2.add(cnt,v,w),las=cnt;
}
for(int i=T1.head[x];i;i=T1.e[i].nex)
{
int v=T1.e[i].v;
if(v!=f) dfs1(v,x);
}
}
void dfs2(int x,int f)
{
pos[x]=++ind;mi[0][ind]=dis[x];
for(int i=T2.head[x];i;i=T2.e[i].nex)
{
int v=T2.e[i].v,w=T2.e[i].w;
if(v==f) continue;
dis[v]=dis[x]+w;dfs2(v,x);mi[0][++ind]=dis[x];
}
}
ll lca(int x,int y)
{
x=pos[x];y=pos[y];
if(x>y) swap(x,y);
int t=Log[y-x+1];
return min(mi[t][x],mi[t][y-fc[t]+1]);
}
ll getdis(int x,int y){return dis[x]+dis[y]-lca(x,y)*2;}
void initlca()
{
for(int i=2;i<N*2;++i) Log[i]=Log[i>>1]+1;
fc[0]=1;for(int i=1;i<20;++i) fc[i]=fc[i-1]<<1;
for(int j=1;j<20;++j) for(int i=1;i+fc[j]-1<=ind;++i)
mi[j][i]=min(mi[j-1][i],mi[j-1][i+fc[j-1]]);
}
void getroot(int x,int f)
{
siz[x]=1;mx[x]=0;
for(int i=T2.head[x];i;i=T2.e[i].nex)
{
int v=T2.e[i].v;
if(vis[v] || v==f) continue;
getroot(v,x);siz[x]+=siz[v];mx[x]=max(mx[x],siz[v]);
}
mx[x]=max(mx[x],sum-siz[x]);
if(mx[x]<mx[root]) root=x;
}
void solve(int x)
{
vis[x]=1;tr[x].id=x;
for(int i=T2.head[x];i;i=T2.e[i].nex)
{
int v=T2.e[i].v;
if(vis[v]) continue;
sum=siz[v];root=0;getroot(v,x);dp[root]=dp[x]+1;
for(int j=0;j<dp[x];++j) st[root].pb(st[x][j]);
for(int j=0;j<3;++j) if(!tr[x].ch[j])
{
tr[x].ch[j]=root;st[root].pb(j);
break;
}
solve(root);
}
}
void insert(int x,int &y,int a,int b,int f)
{
y=++dtsz;int z=tr[x].id;
//printf("%d %d %d %d %d %d\n",x,y,z,a,b,f);
memcpy(tr[y].ch,tr[x].ch,sizeof(tr[x].ch));tr[y].id=z;
tr[y].sz=tr[x].sz+b;tr[y].s1=tr[x].s1+getdis(z,a)*b;tr[y].s2=tr[x].s2;
if(f) tr[y].s2+=getdis(tr[f].id,a)*b;
if(tr[y].id==a) return;
insert(tr[x].ch[st[a][dp[z]]],tr[y].ch[st[a][dp[z]]],a,b,y);
}
ll query(int x,int y)
{
ll res=0;
for(int i=0;i<dp[y];++i)
{
int u=tr[x].ch[st[y][i]];
res+=(tr[x].sz-tr[u].sz)*getdis(tr[x].id,y)+(tr[x].s1-tr[u].s2);
x=u;
}
return res+tr[x].s1;
}
}
using namespace Graph;
namespace DreamLolita
{
int p[N];
ll ans;
void solve()
{
cnt=n=read();m=read();
for(int i=1;i<=n;++i) p[i]=read();
for(int i=1;i<n;++i)
{
int u=read(),v=read(),w=read();
++du[u];++du[v];T1.add(u,v,w);
}
dfs1(1,0);dfs2(1,0);initlca();
mx[0]=sum=cnt;getroot(1,0);rt[0]=root;Graph::solve(root);
dtsz=cnt;for(int i=1;i<=n;++i) insert(rt[i-1],rt[i],p[i],1,0);
while(m--)
{
if(read()&1)
{
int l=read()^ans,r=read()^ans,v=read()^ans;
ans=query(rt[r],v)-query(rt[l-1],v);
writeln(ans);ans&=msk;
}
else
{
int x=read()^ans;
insert(rt[x-1],rt[x],p[x],0,0);swap(p[x],p[x+1]);insert(rt[x],rt[x],p[x],1,0);
}
}
}
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("CF757G.in","r",stdin);
freopen("CF757G.out","w",stdout);
#endif
DreamLolita::solve();
return 0;
}