“科大讯飞杯”第18届上海大学程序设计联赛春季赛暨高校网络友谊赛 G:血压游戏(虚树+单调栈建树)

因为是同步进行的,所以第i层的不会影响到i+1层,所以我们可以把他们分层处理,对于当前层数,一直往上走,但是分层后他们可能会在某个点汇聚,就是它们的lca,所以我们得把他们所有的lca给求出来,然后建另外一棵树(虚树),对这个树dfs一遍求一下答案,求他们的lca,只要依次从左到右,两两的lca就是了,顺序可通过dfs序从小到大排序,然后对于n个点他们的lca最多 只有n-1个,因为假设求a b c3个点两两的lca, A = lca(a,b),那么a、b与c的lca其实就可以通过A和c的lca来得到。所以最多n-1个,然后最主要就是建虚树的过程,可以通过单调栈来建树,对于第i层,把s压入栈中,然后对于下一个点,求一遍与栈顶 元素top的lca,然后lca依次与top-1比较,直到lca的dfs大于top-1的dfs序的时候结束。因为是 从左到右遍历的点,所以正确性能保证。
部分细节见代码
复杂度O(nlogn)

#pragma GCC optimize(2)
#include
using namespace std;
const int man = 2e5+10;
#define IOS ios::sync_with_stdio(0)
#define ull unsigned ll
#define uint unsigned
#define pai pair
#define pal pair
#define IT iterator
#define pb push_back
#define fi first
#define se second
#define For(i,j,k) for (int i=(int)(j);i<=(int)(k);++i)
#define Rep(i,j,k) for (int i=(int)(j);i>=(int)(k);--i)
#define endl '\n'
#define ll long long
const ll mod = 1e9+7;
int n,s;
int a[man],rk[man];
vector<int>sp[man],h[man],x_sp[man];
int dep[man],fa[man][20],max_dep;
int cnt = 0;

void dfs(int u,int f){
	rk[u] = ++cnt;
    dep[u] = dep[f] + 1;
	h[dep[u]].emplace_back(u);
	max_dep = max(max_dep,dep[u]);
    fa[u][0] = f;
    for(int i = 1;i < 20;i++){
        fa[u][i] = fa[fa[u][i-1]][i-1];
    }
    for(int i = 0;i < sp[u].size();i++){
        int v = sp[u][i];
        if(v==f)continue;
        dfs(v,u);
    }
}

int lca(int u,int v){
    if(dep[u]<dep[v])swap(u,v);
    for(int i = 19;i >= 0;i--){
        if(dep[fa[u][i]]>=dep[v]){
            u = fa[u][i];
        }
    }
    if(u==v)return v;
    for(int i = 19;i >= 0;i--){
        if(fa[u][i]!=fa[v][i]){//因为u,v的祖先的祖先也是u,v的祖先
            u = fa[u][i];
            v = fa[v][i];
        }
    }
    return fa[u][0];
}

int sta[man],top;

void insert(int u){
	if(1==top){
		sta[++top] = u;
		return;
	}
	int fa = lca(sta[top],u);
	while(top>=2&&rk[fa]<=rk[sta[top-1]]){
		x_sp[sta[top-1]].emplace_back(sta[top]);
		--top;
	}
	if(fa!=sta[top]){
		x_sp[fa].emplace_back(sta[top]);
		sta[top] = fa;
	}
	sta[++top] = u;
}

ll dp(int u,int f){
	if(x_sp[u].size()==0){
		return a[u];
	}
	ll ans = 0;
	for(auto v:x_sp[u]){
		if(v==f)continue;
		ll tp = dp(v,u);
		ans += tp>1 ? max(1ll,tp-(dep[v]-dep[u])) : tp;
	}
	x_sp[u].clear();
	//printf("u:%d as:%lld\n",u,ans);
	return ans ;
}


int main() {
	#ifndef ONLINE_JUDGE
		//freopen("in.txt", "r", stdin);
		//freopen("out.txt","w",stdout);
	#endif
	scanf("%d%d",&n,&s);
	For(i,1,n){
		scanf("%d",a+i);
	}
	For(i,1,n-1){
		int u,v;
		scanf("%d%d",&u,&v);
		sp[u].emplace_back(v);
		sp[v].emplace_back(u);
	}
	dfs(s,0);
	ll ans = a[s]>1 ? a[s]-1:a[s];
	For(i,2,max_dep){
		sort(h[i].begin(),h[i].end(),[](const auto &a,const auto &b){return rk[a] < rk[b];});
		top = 0;
		sta[++top] = s;
		x_sp[s].clear();
		For(j,0,h[i].size()-1){
			x_sp[h[i][j]].clear();
			insert(h[i][j]);
		}
		while(top>1){
			x_sp[sta[top-1]].emplace_back(sta[top]);
			--top;
		}
		ll res = dp(s,0);
		ans += res>1 ? max(1ll,res - 1) : res;
		//printf("res:%d\n",res);
	}
	printf("%lld\n",ans);
	return 0;
}

你可能感兴趣的:(牛客,LCA,虚树)