• [ZJOI2008] 骑士


    题目类型:基环树DP

    传送门:>Here<

    题意:给出一棵基环树,每个节点有点权。任意一条边的两端的节点不能都选,问最大和

    解题思路

    所谓基环树,就是只有一个简单环的树

    我们熟知的树有(N)个节点(N-1)条边。再加入一条边必定形成环,且只有一个环。那么基环树就是(N)个节点(N)条边的树(严格来说不能叫树,而是仙人掌)。

    因此我们如果想做树形(DP),必须删去环内的一条边。设删去边((u,v))。于是我们以(u)为根节点做一次(DP),注意此时规定不能取(v)这个点。由于没有取(v),因此需要再考虑取(v)的情况。因此以(v)为根节点再做一次(DP)

    如何保证在(DP)时保证不取到对应的那个点?权值赋值为负数即可,这样选他肯定不会优,所以不会去选

    Code

    /*By DennyQi*/
    #include <cstdio>
    #include <queue>
    #include <cstring>
    #include <algorithm>
    #define  r  read()
    #define  Max(a,b)  (((a)>(b)) ? (a) : (b))
    #define  Min(a,b)  (((a)<(b)) ? (a) : (b))
    using namespace std;
    typedef long long ll;
    const int MAXN = 1000010;
    const int MAXM = 2000010;
    const int INF = 1061109567;
    inline int read(){
        int x = 0; int w = 1; register int c = getchar();
        while(c ^ '-' && (c < '0' || c > '9')) c = getchar();
        if(c == '-') w = -1, c = getchar();
        while(c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0', c = getchar(); return x * w;
    }
    int N,x,has_root,s,e,EE;
    ll ans;
    int first[MAXM],nxt[MAXM],to[MAXM],num_edge=-1;
    int val[MAXN],vis[MAXN];
    ll f[MAXN][2];
    inline void add(int u, int v){
    	to[++num_edge] = v;
    	nxt[num_edge] = first[u];
    	first[u] = num_edge;
    }
    inline void SearchRoot(int u, int father){
    	int v;
    	vis[u] = 1;
    	for(int i = first[u]; i != -1; i = nxt[i]){
    		if((v = to[i]) == father) continue;
    		if(!vis[v]){
    			SearchRoot(v, u);
    		}
    		else{
    			s = u, e = v;
    			EE = i;
    			continue;
    		}
    	}
    }
    void DP(int u, int father){
    	int v;
    	f[u][0] = 0, f[u][1] = 1LL * val[u];
    	for(int i = first[u]; i != -1; i = nxt[i]){
    		if((v = to[i]) == father) continue;
    		if(i == EE || i == (EE^1)) continue;
    		DP(v, u);
    		f[u][1] += f[v][0];
    		f[u][0] += Max(f[v][0], f[v][1]);
    	}
    }
    int main(){
    	N = r;
    	memset(first,-1,sizeof(first));
    	for(int i = 1; i <= N; ++i){
    		val[i] = r;
    		x = r;
    		add(i, x), add(x, i);
    	}
    	for(int i = 1; i <= N; ++i){
    		if(!vis[i]){
    			s = e = 0;
    			SearchRoot(i, -1);
    			if(!s){
    				DP(i, -1);
    				ans += Max(f[i][0], f[i][1]);
    				continue;
    			}
    			
    			int tmp = val[e];
    			val[e] = -INF;
    			DP(s, -1);
    			ll res = Max(f[s][0], f[s][1]);
    			val[e] = tmp;
    			
    			tmp = val[s];
    			val[s] = -INF;
    			DP(e, -1);
    			val[s] = tmp;
    			res = Max(res, Max(f[e][0],f[e][1]));
    			ans += res;
    		}
    	}
    	printf("%lld", ans);
    	return 0;
    } 
    
  • 相关阅读:
    QQ列表展示
    拖动条SeekBar
    信息提示框、对话框
    键盘事件、触摸事件
    时间日期事件处理,长按事件
    图片切换示例
    索引值的应用
    this的应用
    自定义属性应用1
    自定义属性应用
  • 原文地址:https://www.cnblogs.com/qixingzhi/p/9504663.html
Copyright © 2020-2023  润新知