CF757G Can Bash Save the Day?(可持久化點分樹)

題目
這個題在CF上跑了15min才跑出來、、

真就可持久化唄。
考慮求一個點到一個點集的距離和。
可以用動態點分治也就是點分樹來維護點集加刪點和詢問操作。
對於這個題,差分一下變成:
多次詢問前1...r1...r個組成的點集到一個點的距離。
那麼就可以可持久化點分樹維護1...r1...r的每個版本的點分樹。
對於修改操作,發現其實就是對於xx這個位置的單點修改,後面的版本都不會變。
維護可持久化點分樹的過程就是相當於維護一個多叉的可持久化線段樹。。。可以用dfs序判斷往哪個兒子走。
注意到可持久化的過程是需要複製兒子鏈接的。
所以就把樹三叉化即可。
常數×2\times 2
但是這個做法仍然是這個題最不卡空間的做法,用腳開空間都能過。
AC Code\rm AC \ Code

#include<bits/stdc++.h>
#define maxn 400005
#define maxp maxn * 20
#define LL long long
#define lim 20
#define ADJ(i,u) for(int i=info[u],v;i;i=Prev[i])
using namespace std;
 
int n,q,tot,a[maxn],rt[maxn];
int info[maxn],Prev[maxn<<1],to[maxn<<1],cst[maxn<<1],cnt_e;
void Node(int u,int v,int c){ Prev[++cnt_e]=info[u],info[u]=cnt_e,to[cnt_e]=v,cst[cnt_e]=c; }
vector<pair<int,int> >G[maxn];
 
void dfs0(int u,int ff){
	int p=u;
	for(int i=0,v;i<G[u].size();i++) if((v=G[u][i].first)^ff){
		if(G[u].size() > 3 && i>=1){
			Node(p,++tot,0),Node(tot,p,0);
			Node(tot,v,G[u][i].second),Node(v,tot,G[u][i].second);
			p = tot;
		}
		else Node(u,v,G[u][i].second),Node(v,u,G[u][i].second);
		dfs0(v,u);
	}
}
 
LL dis[lim][maxn],sm[maxp],zsm[maxp],zcnt[maxp],cnt[maxp],cnt_p;
int vis[maxn],id[maxp],st[maxn],ed[maxn],sz[maxn],dep[maxn];
int E[maxp][3],cte[maxp];
 
void dfs1(int u,int ff,int tsz,int &mn,int &rt){
	int mx = 0;sz[u] = 1;
	ADJ(i,u) if((v=to[i])^ff && !vis[v]){
		dfs1(v,u,tsz,mn,rt);
		sz[u]+=sz[v];
		mx=max(mx,sz[v]);
	} 
	if((mx=max(mx,tsz-sz[u])) < mn)
		mn = mx , rt = u;
}
 
int gert(int u,int tsz){
	int mn = 0x3f3f3f3f  , rt= -1;
	dfs1(u,0,tsz,mn,rt);
	return rt;
}
 
void ser(int u,int ff,LL d,int dp){
	sz[u] =1;
	dis[dp][u] = d;
//	printf("@%d %d %d\n",dp,u,d);
	ADJ(i,u) if((v=to[i])^ff && !vis[v]){
		ser(v,u,d+cst[i],dp);
		sz[u] += sz[v];
	}
}
 
void Build(int u){
	vis[u] = 1;
//printf("@%d\n",u);
	ser(u,0,0,dep[u]);
//	puts("##");
	ADJ(i,u) if(!vis[v=to[i]]){
		int t= gert(v,sz[v]);
		dep[t] = dep[u] + 1;
		E[u][cte[u]++] = t;
		Build(t);
	}
}
 
void dfs2(int u){ 
	static int tot = 0;
	st[u] = ++tot;id[u] = u;
	for(int i=0,v;i<cte[u];i++){
		v=E[u][i];
		dfs2(v);
	}
	ed[u] = tot;
}
 
void ins(int &u,int p){
	id[++cnt_p] = id[u] , sm[cnt_p] = sm[u] , cnt[cnt_p] = cnt[u] , zsm[cnt_p] = zsm[u] , zcnt[cnt_p] = zcnt[u];
	memcpy(E[cnt_p],E[u],sizeof E[u]),cte[cnt_p]=cte[u];
	int nu = id[u];u = cnt_p;
//	printf("@%d %d %lld\n",dep[nu],p,dis[dep[nu]][p]);
	sm[u] += dis[dep[nu]][p];
	cnt[u] ++;
	for(int i=0,v;i<cte[u];i++) if(st[id[v=E[u][i]]] <= st[p] && st[p] <= ed[id[v]]){
		ins(E[u][i],p);v = E[u][i];
		zsm[v] += dis[dep[nu]][p];
		zcnt[v] ++;
	}
}
 
LL qry(int u,int p){
	int nu = id[u] ;
	LL r = sm[u] + cnt[u] * dis[dep[nu]][p];
	//printf("@%d %d %lld %d %lld\n",u,p,r,nu,dis[dep[nu]][p]);
	for(int i=0,v;i<cte[u];i++) if(st[id[v=E[u][i]]] <= st[p] && st[p] <= ed[id[v]])
		r += qry(v,p) - (zsm[v] + zcnt[v] * dis[dep[nu]][p]);
	return r;
}
 
int main(){
	scanf("%d%d",&n,&q);tot = n;
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	for(int i=1;i<n;i++){
		int u,v,c;
		scanf("%d%d%d",&u,&v,&c);
		G[u].push_back(make_pair(v,c));
		G[v].push_back(make_pair(u,c));
	}
	dfs0(1,0);
	rt[0]  =gert(1,tot);
	Build(rt[0]);
	cnt_p = tot;
	dfs2(rt[0]);
	for(int i=1;i<=n;i++){
		rt[i] = rt[i-1];
		ins(rt[i],a[i]);
	}
	LL ans = 0;
	for(int t,l,r,v;q--;){
		scanf("%d%d",&t,&l);
		ans %= (1<<30);
		l ^= ans;
		if(t == 1){
			scanf("%d%d",&r,&v);
			r ^= ans , v ^= ans;
		//	printf("##");
			ans = qry(rt[r] , v) - qry(rt[l-1] , v);
			printf("%lld\n",ans);
		}
		else{
			swap(a[l],a[l+1]);
			rt[l] = rt[l-1];
			ins(rt[l],a[l]);
		}
	}
} 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章