W
e
l
c
o
m
e
: )

CF757G Can Bash Save the Day? (复健 Day 1)

先差分为 \(Q(r)-Q(l-1)\)\(Q(i)=\sum_{j=1}^{i} \operatorname{dis}(p_j, x)\)

树上在线路径优先考虑点分树,先想询问怎么做,我们记 \(f_i\) 为点分树上 \(i\) 点子树内所有前缀的 \(p\) 点到 \(i\) 的距离和,并记录 \(g_i\)\(i\) 子树内的 \(p_i\) 点到 \(fa_i\) 的距离,\(h_i\)\(i\) 子树内 \(p\) 点的个数,那么对于每次询问,我们在点分树上跳,点 \(j\) 的父亲 \(i\) 贡献即为 \((f_i-g_j)+(h_i-h_j)\times\operatorname{dis}(i, x)\)\(j\)\(x\) 到根路径上的点,特别地,\(i=x\) 的时候关于 \(j\) 的值视为 0 即可),用 \(O(1) \operatorname{LCA}\) 能做到 \(O(\log n)\) 处理查询。

那么加入一个点的贡献时,我们只需快速维护 \(f, g, h\) 即可,点分树深度为 \(\log n\),因此可以直接暴力修改。

交换操作就是对 \(x\) 处的前缀修改,因此我们要做的就是可持久化一个数组,直接主席树的话空间 $O((n+m)\log^2) $ 有点紧,不知道能不能过。

思考一下本质,为什么我们无法绕过主席树?我们每次操作只会修改一条到根的链的结点,但是可持久化需要保留所有儿子的信息,一次暴力复制的时空复杂度都可以很轻松的卡到 \(O(n)\) 级别,我们需要操作的就是将儿子的信息尽量简化,由此便可以联想到边分治中的三度化,不过注意此时应该是原树三度化后再点分树,否则会失去原来 \(\log\) 层的特性。

Code:

#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <cctype>
#include <vector>
#include <queue>
#include <bitset> 
#define pb push_back
#define mp make_pair
#define st first
#define nd second
using namespace std;
typedef long long ll;
typedef pair <int, int> Pii;
const int INF=0x3f3f3f3f;
const int cp=1<<30;
inline int plust(int x, int y){x+=y;if(x>=cp) x-=cp;if(x<0) x+=cp;return x;}
inline int minut(int x, int y){x-=y;if(x>=cp) x-=cp;if(x<0) x+=cp;return x;}
inline int read(){
	char ch=getchar();int x=0, f=1;
	while(!isdigit(ch)){if(ch=='-') f=-1; ch=getchar();}
	while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
	return x*f;
}
inline void write(int x){
    if(x<0) putchar('-'), x=-x;
    if(x>9) write(x/10);
    putchar(x%10+'0');
}
inline int ksm(int a, int b=cp-2){
	int ret=1;
	for(; b; b>>=1, a=1ll*a*a%cp)
		if(b&1) ret=1ll*ret*a%cp;
	return ret;
}
const int N=2e5+5;
int n, m, p[N], ecnt, cnt, ROOT, Rt, sMn, ndc, tot, tim;
int h[N], vis[N<<1], dep[N<<1], siz[N<<1];
int in[N<<1], fa[N<<1], lg[N<<2], ST[N<<2][21], rt[N];
ll dis[N<<1];
struct Edge{int to, nxt, w;}d[N<<1];
void add(int x, int y, int z){d[++ecnt]=(Edge){y, h[x], z};h[x]=ecnt;}
vector <Pii> G[N<<1];
struct node{int id, sn[3], h;ll f, g;}tr[N*70];
int Mx(int x, int y){return dep[x]<dep[y]?x:y;}
int LCA(int x, int y){
	x=in[x], y=in[y];if(x>y) swap(x, y);
	int k=lg[y-x+1];return Mx(ST[x][k], ST[y-(1<<k)+1][k]);
}
ll dist(int x, int y){if(!x||!y) return 0;return dis[x]+dis[y]-dis[LCA(x, y)]*2;}
void G_add(int x, int y, int w){G[x].pb(mp(y, w)), G[y].pb(mp(x, w));}
void rebuild(int x){
	vis[x]=tim;int lst=0;
	for(int i=h[x], v; i; i=d[i].nxt)
		if(vis[v=d[i].to]<tim){
			if(!lst) G_add(x, v, d[i].w), lst=x;
			else ++ndc, G_add(lst, ndc, 0), G_add(ndc, v, d[i].w), lst=ndc;
			rebuild(v);
		}
}
void dfs(int x){
	ST[++cnt][0]=x, in[x]=cnt;
	for(auto v:G[x])
		if(!dep[v.st]) 
			dep[v.st]=dep[x]+1, dis[v.st]=dis[x]+v.nd, dfs(v.st), ST[++cnt][0]=x;
}
void findrt(int x, int all){
	vis[x]=tim, siz[x]=1;int sMx=0;
	for(auto v:G[x])
		if(vis[v.st]<tim) 
			findrt(v.st, all), siz[x]+=siz[v.st], sMx=max(sMx, siz[v.st]);
	sMx=max(sMx, all-siz[x]);if(sMn>sMx) sMn=sMx, Rt=x;
}
void add(int x, int y){
	if(tr[x].sn[1]) tr[x].sn[2]=y;
	else if(tr[x].sn[0]) tr[x].sn[1]=y;
	else tr[x].sn[0]=y;
	fa[y]=x;
}
void dfz(int x){
	++tim, findrt(x, siz[x]), vis[x]=INF;
	for(auto v:G[x])
		if(vis[v.st]<INF) 
			++tim, Rt=v.st, sMn=siz[v.st], 
			findrt(v.st, siz[v.st]), add(x, Rt), dfz(Rt);
}
#define id(x) tr[x].id
#define lc(x) tr[x].sn[0]
#define mc(x) tr[x].sn[1]
#define rc(x) tr[x].sn[2]
#define f(x) tr[x].f
#define g(x) tr[x].g
#define h(x) tr[x].h
void renew(int &x, int v, int type, ll el){
	tr[++tot]=tr[x], x=tot;
	h(x)+=type, g(x)+=el, f(x)+=(el=dist(v, id(x))*type);
	if(vis[id(lc(x))]==tim) renew(lc(x), v, type, el);
	if(vis[id(mc(x))]==tim) renew(mc(x), v, type, el);
	if(vis[id(rc(x))]==tim) renew(rc(x), v, type, el);
}
void update(int idx, int type){
	int pos=p[idx];++tim;
	for(int x=pos; x; x=fa[x]) vis[x]=tim;
	rt[idx]=rt[idx-1];
	renew(rt[idx], pos, type, 0);
}
ll res;
int calc(int x, int v){
	int t=0;
	if(vis[id(lc(x))]==tim) t=calc(lc(x), v);
	if(vis[id(mc(x))]==tim) t=calc(mc(x), v);
	if(vis[id(rc(x))]==tim) t=calc(rc(x), v);
	return (res+=f(x)-g(t)+dist(id(x), v)*(h(x)-h(t)), x);
}
ll query(int ver, int pos){
	res=0;++tim;
	for(int x=pos; x; x=fa[x]) vis[x]=tim;
	calc(rt[ver], pos);
	return res;
}
#undef id
#undef lc
#undef mc
#undef rc
#undef f
#undef g
#undef h
signed main(){
	n=read(), m=read();
	for(int i=1; i<=n; ++i) p[i]=read();
	for(int i=1, a, b, c; i<n; ++i)
		a=read(), b=read(), c=read(),
		add(a, b, c), add(b, a, c);
	++tim, ndc=n, rebuild(1);
	dfs(dep[1]=1);
	dep[0]=n+1, lg[0]=-1;
	for(int i=1; i<=cnt; ++i) lg[i]=lg[i>>1]+1;
	for(int i=1; i<=20; ++i)
		for(int x=1; x+(1<<i)-1<=cnt; ++x)
			ST[x][i]=Mx(ST[x][i-1], ST[x+(1<<i-1)][i-1]);
	Rt=1, sMn=ndc, ++tim, findrt(1, ndc), dfz(rt[0]=ROOT=Rt);
	memset(vis, 0, sizeof(vis)), tim=0;
	for(int i=1; i<=ndc; ++i) tr[++tot].id=i;
	for(int i=1; i<=n; ++i) update(i, 1);
	ll ans=0;
	for(int i=1; i<=m; ++i){
		int opt=read();
		if(opt&1){
			int l=(ans%cp)^read(), r=(ans%cp)^read(), x=(ans%cp)^read();
			printf("%lld\n", ans=query(r, x)-query(l-1, x));
		}
		else{
			int x=(ans%cp)^read();
			update(x, -1), swap(p[x], p[x+1]), update(x, 1);
		}
	}
	return 0;
}
 
posted @ 2023-01-07 21:03  127_127_127  阅读(40)  评论(0编辑  收藏  举报