“科大訊飛杯”第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<bits/stdc++.h>
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<int,int>
#define pal pair<ll,ll>
#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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章