【知識小結】圓方樹 && 廣義圓方樹

例題

雜事:datamaker

感覺仙人掌好難造,我是在樹上隨機加邊

#include<bits/stdc++.h>
using namespace std;

#define rep(i,l,r) for(register int i = l ; i <= r ; i++)
#define repd(i,r,l) for(register int i = r ; i >= l ; i--)
#define rvc(i,S) for(register int i = 0 ; i < (int)S.size() ; i++)
#define rvcd(i,S) for(register int i = ((int)S.size()) - 1 ; i >= 0 ; i--)
#define fore(i,x)for (register int i = head[x] ; i ; i = e[i].next)
#define forup(i,l,r) for (register int i = l ; i <= r ; i += lowbit(i))
#define fordown(i,id) for (register int i = id ; i ; i -= lowbit(i))
#define pb push_back
#define prev prev_
#define stack stack_
#define mp make_pair
#define fi first
#define se second
#define lowbit(x) ((x)&(-(x)))

typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair<int,int> pr;

const ld inf = 2e18;
const int N = 3e6 + 10;
const int maxn = 100020;
const ll mod = 1e9 + 7;

inline ll power(ll x,ll y){
	y = ((y % (mod - 1)) + (mod - 1)) % (mod - 1);
//	if ( y < 0 ) return power(power(x,-y),mod - 2);
	ll res = 1;
	while ( y ){
		if ( y & 1 ) res = res * x % mod;
		x = x * x % mod;
		y >>= 1;
	}
	return res;
}

set <pr> s;
vector <int> e[maxn];
int fa[maxn],dth[maxn],tag[maxn];

void adde(int x,int y){
	e[x].pb(y);
	e[y].pb(x);
}
void dfs(int x){
	rvc(i,e[x]){
		int to = e[x][i];
		if ( to == fa[x] ) continue;
		fa[to] = x , dth[to] = dth[x] + 1;
		dfs(to);
	}
}
bool lca(int x,int y){
	int flag = 0;
	while ( x != y ){
		if ( dth[x] < dth[y] ) swap(x,y);
		flag |= tag[x] , x = fa[x];
	}
	flag |= tag[x];
	return flag ^ 1;
}
void cov(int x,int y){
	while ( x != y ){
		if ( dth[x] < dth[y] ) swap(x,y);
		tag[x] = 1 , x = fa[x];
	}
	tag[x] = 1;
}
int main(){
	freopen("1.cnt","r",stdin);
	int cnt;
	scanf("%d",&cnt);
	fclose(stdin);
	freopen("1.cnt","w",stdout);
	cout<<++cnt;
	fclose(stdout);
	srand(cnt + time(0));
	freopen("input.txt","w",stdout);
	int n = 20,m = n + rand() % 2;
	cout<<n<<" "<<m<<endl;
	rep(i,1,n) cout<<rand() % 100 + 1<<" ";
	cout<<endl;
	rep(i,2,n){
		int x = rand() % (i - 1) + 1;
		adde(i,x);
		cout<<i<<" "<<x<<endl;
		s.insert(mp(x,i)) , s.insert(mp(i,x));
	}
	dfs(1);
	rep(i,1,m - n + 1){
		int x = rand() % n + 1 , y = rand() % n + 1;
		while ( x == y || !lca(x,y) || s.find(mp(x,y)) != s.end() ) x = rand() % n + 1 , y = rand() % n + 1;
		cov(x,y) , s.insert(mp(x,y)) , s.insert(mp(y,x));
		cout<<x<<" "<<y<<endl;
	}

}

1. 求仙人掌最大權獨立集

一道40min就應該ok的圓方樹DP。
犯了兩個SB錯誤!
1. 特判方點忘了往下繼續dfs
2. 往下dfs但是環上DP用的數組標號,數組被下面的點修改
都是非常簡單。但我經常犯的錯誤!
從訓練到下來總共調了1小時20分鐘,非常浪費時間!

#include<bits/stdc++.h>
using namespace std;
#define pb push_back
#define rep(i,l,r) for (int i = l ; i <= r ; i++)

const int maxn = 3e5 + 20;
const int inf = 1e9;

vector <int> e[maxn],e2[maxn];
vector <int> cur;

int tops,n,m,dfn[maxn],low[maxn],tot,tag[maxn],val[maxn],dfstime,st[maxn];
int f[maxn][2],h[maxn][2][2],g[2][2];

void adde(int x,int y){
	e[x].pb(y);
	e[y].pb(x);
}
void adde2(int x,int y);
void tarjian(int x,int fa){
	dfn[x] = low[x] = ++dfstime;
	for (int i = 0 ; i < e[x].size() ; i++){
		int to = e[x][i];
		if ( to == fa ) continue;
		if ( !dfn[to] ){
			st[++tops] = to;
			tarjian(to,x);
			low[x] = min(low[to],low[x]);
			if ( low[to] >= dfn[x] ){
				cur.clear();
				do{
					cur.pb(st[tops]);
				}while ( st[tops--] != to );
				if ( cur.size() == 1 ){
					adde2(x,cur[0]);
				}
				else if ( cur.size() > 1 ){
					tag[++tot] = 1;
					adde2(x,tot);
					for (int i = 0 ; i < cur.size() ; i++) adde2(tot,cur[i]);
					//for (int i = 0  ; i < cur.size() ; i++) cout<<cur[i]<<" ";
					//	cout<<"end circle\n";
				}
			}
		}
		else{
			low[x] = min(dfn[to],low[x]);
		}
	}	
}
#define e e2
void adde2(int x,int y){
//	cout<<x<<" "<<y<<endl;
	e[x].pb(y);
	e[y].pb(x);
}
void build(){
	tot = n;
	for (int i = 1 ; i <= n ; i++) if ( !dfn[i] ) tarjian(i,0);
	//for (int i = 1 ; i <= n ; i++) cout<<dfn[i]<<" "<<low[i]<<endl;
}
void dfs(int x,int fa){
	if ( !tag[x] ){
		f[x][0] = 0 , f[x][1] = val[x];
		for (int i = 0 ; i < e[x].size() ; i++){
			int to = e[x][i];
			if ( to == fa ) continue;
			dfs(to,x);
			if ( !tag[to] ){
				int w = max(f[to][1],f[to][0]);
				//g[x][0] = f[x][0] , g[x][1] = f[x][1] , f[x][0] = f[x][1] = 0;
				f[x][0] += w;
				f[x][1] += f[to][0];
			}
			else{
				f[x][0] += f[to][0];
				f[x][1] += f[to][1] - val[x];
			}
		}	
		return;
	}
	h[x][0][1] = h[x][1][0] = -inf , h[x][0][0] = 0 , h[x][1][1] = val[e[x][0]];
	for (int i = 1 ; i < e[x].size() ; i++){
		int to = e[x][i];
		dfs(to,x); //忘了往下遞歸!
		memcpy(g,h[x],sizeof(h[x])); //一定要注意遞歸下去的數組會改變。不能用標號h[i - 1]!!!

		h[x][1][1] = g[1][0] + f[to][1];
		h[x][1][0] = max(g[1][0],g[1][1]) + f[to][0];
		h[x][0][1] = g[0][0] + f[to][1];
		h[x][0][0] = max(g[0][0],g[0][1]) + f[to][0];
		
	}
	f[x][0] = max(h[x][0][1],h[x][0][0]);
	f[x][1] = h[x][1][0];
}
#undef e

int main(){
//	freopen("input.txt","r",stdin);
	scanf("%d %d",&n,&m);
	for (int i = 1 ; i <= n ; i++) scanf("%d",&val[i]);
	for (int i = 1 ; i <= m ; i++){
		int x,y;
		scanf("%d %d",&x,&y);
		adde(x,y);
	}
	build();
	dfs(1,0);
//	for (int i = 1;  i <= tot ; i++) cout<<i<<" "<<f[i][0]<<" "<<f[i][1]<<endl;
	cout<<max(f[1][0],f[1][1])<<endl;
}

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