JZOJ6642. 【GDOI20205.20模擬】classroom

Description

在這裏插入圖片描述在這裏插入圖片描述

Solution

  • 一道集大成的數據結構題。
  • 假設W(x)W(x)表示xx到最近的樓梯的距離。
  • 根爲xx答案爲——跨層的貢獻,所有點到xx的距離和,所有點到xx路徑上Min(W(p))Min(W(p))的和。
  • 第一個可以排序簡單計算。
  • 第二個可以虛樹上換根DP。
  • 第三個由於是最小值,可以考慮並查集。可以直接並查集然後打tag計算答案。也可以預先建出克魯斯卡爾重構樹(注意這裏沒有新加的點,從大到小加入,那麼兩點路徑上的最小值就是它們的LCA的W),然後建虛樹,再在上面換根DP。
  • 注意到同層不需要走樓梯,所以用總的Min()\sum Min()減去同層的Min()\sum Min()
  • 億點點細節。
  • O(n log n+m log m)O(n\ log \ n+m\ log\ m)
  • 當然你可以通過離線的方式將所有排序以一種類似桶排的方式掛到樹上,做到O(m)O(m)排序,以及預處理ST表O(1)O(1)求LCA,但是性價比太低了
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define maxn 200005
#define maxm 1000005
#define maxp 20
#define ll long long 
using namespace std;

int H,n,m,Q,i,j,k,c[maxn],W[maxn],opr[maxm];
int em,e[maxn*2],nx[maxn*2],ls[maxn]; 
ll dis[maxn],F1[maxn],F2[maxn],ans;
struct node{int x,h;} a[maxm];
int cmp(node a,node b){return a.h<b.h||a.h==b.h&&a.x<b.x;}
int cmp1(int i,int j){return W[i]>W[j];}

void read(int &x){
	x=0; char ch=getchar();
	for(;ch<'0'||ch>'9';ch=getchar());
	for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
}

struct Graph{
	int em,e[maxn*2],nx[maxn*2],ls[maxn];
	void insert(int x,int y){
		em++; e[em]=y; nx[em]=ls[x]; ls[x]=em;
		em++; e[em]=x; nx[em]=ls[y]; ls[y]=em;
	}	
	
	int t,w,d[maxn],rt;
	void GetW(){
		rt=1;for(i=1;i<=n;i++) W[i]=-1;
		t=w=0; for(i=1;i<=n;i++) if (c[i]) d[++w]=i,W[i]=0;
		while (t<w){
			int x=d[++t];
			for(i=ls[x];i;i=nx[i]) if (W[e[i]]==-1)
				d[++w]=e[i],W[e[i]]=W[x]+1;
		}
	}
	
	int p[maxn],bz[maxn];
	void build();
	
	int totd,dfn[maxn],fa[maxn][maxp],dep[maxn],bz0[maxn];
	void DFS(int x,int p){
		fa[x][0]=p,dfn[x]=++totd,dep[x]=dep[p]+1;
		for(int i=1;i<maxp;i++) fa[x][i]=fa[fa[x][i-1]][i-1];
		for(int i=ls[x];i;i=nx[i]) if (e[i]!=p)
			DFS(e[i],x);
	}
	
	int getlca(int x,int y){
		if (dep[x]<dep[y]) swap(x,y);
		for(int i=maxp-1;i>=0;i--) if (dep[fa[x][i]]>=dep[y]) x=fa[x][i];
		if (x==y) return x;
		for(int i=maxp-1;i>=0;i--) if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
		return fa[x][0];
	}
	
	int em0,e0[maxn*2],nx0[maxn*2],ls0[maxn*2],B[maxn];
	void insert0(int x,int y){
		em0++; e0[em0]=y; nx0[em0]=ls0[x]; ls0[x]=em0;
		em0++; e0[em0]=x; nx0[em0]=ls0[y]; ls0[y]=em0;
	}
	
	int tp[maxn];
	void maketree(){
		em0=0,t=0,w=1,d[w]=rt,ls0[rt]=0,B[B[0]=1]=rt;
		for(int i=1;i<=opr[0];i++) if (opr[i]!=rt&&(i==1||opr[i]!=opr[i-1])){
			int p=opr[i],x=d[w],lca=getlca(x,p);
			if (lca==x) d[++w]=p,ls0[p]=0,B[++B[0]]=p; else {
				while (dfn[lca]<dfn[d[w-1]])
					insert0(d[w-1],d[w]),w--;
				if (dfn[lca]>dfn[d[w-1]]) {
					ls0[lca]=ls0[p]=0,insert0(lca,d[w]),w--;
					d[++w]=lca,d[++w]=p,B[++B[0]]=lca,B[++B[0]]=p;
				} else {
					insert0(d[w-1],d[w]),w--;
					ls0[p]=0,d[++w]=p,B[++B[0]]=p;
				}
			}
		}
		while (w>1) insert0(d[w-1],d[w]),w--;
		for(int i=1;i<=B[0];i++) tp[B[i]]=0;
		for(int i=1;i<=opr[0];i++) tp[opr[i]]=1;
	}
	
	ll f[maxn],sz[maxn];
	void DFS1(int x,int p){
		for(int i=ls0[x];i;i=nx0[i]) if (e0[i]!=p){
			DFS1(e0[i],x),f[x]+=f[e0[i]]+sz[e0[i]]*(dep[e0[i]]-dep[x]);
			sz[x]+=sz[e0[i]];
		}
	}
	
	void DFS2(int x,int p,ll sum){
		if (tp[x]) dis[x]=f[x]+sum;
		for(int i=ls0[x];i;i=nx0[i]) if (e0[i]!=p){
			int y=e0[i];
			DFS2(y,x,sum+f[x]-f[y]+1ll*(-sz[y]*2+opr[0])*(dep[y]-dep[x]));
		}
	}
	
	void dp1(){
		for(int i=1;i<=B[0];i++) f[B[i]]=sz[B[i]]=0;
		for(int i=1;i<=opr[0];i++) sz[opr[i]]++;
		DFS1(rt,0),DFS2(rt,0,0);
	}
	
	void DFS3(int x,int p,ll sum){
		if (tp[x]) F1[x]=(sz[x])*W[x]+sum;
		for(int i=ls0[x];i;i=nx0[i]) if (e0[i]!=p)
			DFS3(e0[i],x,sum+1ll*W[x]*(sz[x]-sz[e0[i]]));
	}
	
	void dp2(){
		for(int i=1;i<=B[0];i++) f[B[i]]=sz[B[i]]=0;
		for(int i=1;i<=opr[0];i++) sz[opr[i]]++;
		DFS1(rt,0);
		DFS3(rt,0,0);
	}
} G,T;

int fat[maxn];
int father(int x){return (fat[x]==x)?x:fat[x]=father(fat[x]);}
void Graph::build(){
	for(i=1;i<=n;i++) p[i]=i,fat[i]=i;
	sort(p+1,p+1+n,cmp1);
	for(i=1;i<=n;i++){
		int x=p[i]; 
		bz[x]=1;
		for(j=G.ls[x];j;j=G.nx[j]) if (bz[G.e[j]]){
			insert(x,father(G.e[j]));
			fat[father(G.e[j])]=x;
		}
	}
	rt=p[n];
}

int cmpG(int i,int j){return G.dfn[i]<G.dfn[j];}
int cmpT(int i,int j){return T.dfn[i]<T.dfn[j];}

ll pres[maxm],nexs[maxm];

int main(){
	read(H),read(n);
	for(i=1;i<=n;i++) read(c[i]);
	for(i=1;i<n;i++) read(j),read(k),G.insert(j,k);
	G.GetW(),G.DFS(1,0);
	T.build(),T.DFS(T.rt,0);
	read(Q);
	while (Q--){
		read(m);
		for(i=1;i<=m;i++) read(a[i].h),read(a[i].x);
		sort(a+1,a+1+m,cmp);
		pres[1]=nexs[m]=0;
		for(i=2;i<=m;i++) pres[i]=pres[i-1]+1ll*(a[i].h-a[i-1].h)*(i-1);
		for(i=m-1;i>=1;i--) nexs[i]=nexs[i+1]+1ll*(a[i+1].h-a[i].h)*(m-i);
		
		opr[0]=m;for(i=1;i<=m;i++) opr[i]=a[i].x;
		sort(opr+1,opr+1+opr[0],cmpG),G.maketree(),G.dp1();
		sort(opr+1,opr+1+opr[0],cmpT),T.maketree(),T.dp2();
		for(i=1;i<=opr[0];i++) F2[opr[i]]=F1[opr[i]];
		
		ans=1e18;
		for(i=1;i<=m;i=j){
			for(j=i;a[j].h==a[i].h&&j<=m;j++);
			opr[0]=0;for(k=i;k<j;k++) opr[++opr[0]]=a[k].x;
			sort(opr+1,opr+1+opr[0],cmpT),T.maketree(),T.dp2();
			for(k=i;k<j;k++) 
				ans=min(ans,pres[k]+nexs[k]+dis[a[k].x]+(F2[a[k].x]-F1[a[k].x])*2);
		}
		printf("%lld\n",ans);
	}
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章