zoukankan      html  css  js  c++  java
  • 清橙A1212:剪枝

    题面

    清橙

    Sol

    一种新的树上(DP)姿势
    从左往右按链(DP)

    做法:
    维护两个栈(S1)(S2)
    (S1)存当前的链
    (S2)存分叉点以下要改的链
    (Dfs),弄一个分叉点,之前的链经过它,并且另一条要转移到的链也经过它
    那么每次在叶节点时就把(S1)最下面的一部分变成(S2)

    转移
    两种情况:
    最大值在(S1)和在(S2)的情况
    那么枚举(S2)(S1)中小于(S2)的枚举的值的点就可以转移,并维护(S1)(S2)的前缀最大值
    再枚举(S2),利用前缀最大值,(S1)的大于等于(S2)的转移

    # include <bits/stdc++.h>
    # define RG register
    # define IL inline
    # define Fill(a, b) memset(a, b, sizeof(a))
    # define File(a) freopen(a".in", "r", stdin), freopen(a".out", "w", stdout)
    using namespace std;
    typedef long long ll;
    const int _(1e5 + 5);
    
    IL int Input(){
        RG int x = 0, z = 1; RG char c = getchar();
        for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1;
        for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
        return x * z;
    }
    
    int n, val[_], f[_], ans = -2e9;
    int fa[_], S1[_], S2[_], id[_], maxv[_];
    vector <int> edge[_];
    
    IL void Dfs(RG int u, RG int top){   //top是分叉点在S1中的位置
    	if(!top) S1[++S1[0]] = u, id[u] = S1[0], f[u] = val[u]; //初始第一条链
    	RG int l = edge[u].size();
    	if(l){    //非叶子节点不做更新
    		for(RG int i = 0; i < l; ++i){
    			RG int v = edge[u][i];
    			if(!i){   //最左边的直接加入S2
    				if(top) S2[++S2[0]] = v;
    				Dfs(v, top);
    			}
    			else S2[S2[0] = 1] = v, Dfs(v, id[u]); //新开一条链
    		}
    		return;
    	}
    	if(!top) return;
    	RG int mx1 = val[S1[top]], maxf = ans, now = top, mx2 = mx1;
    	for(RG int i = 1; i <= S2[0]; ++i){  //最大值在S2中的情况
    		while(now < S1[0] && val[S1[now]] <= mx1){ //计算每个最大值的贡献
    			mx2 = max(mx2, val[S1[now]]);
    			maxf = max(maxf, f[S1[++now]]);
    			maxv[S1[now]] = mx2;  //维护S1前缀最大值
    		}
    		f[S2[i]] = maxf - mx1;  //转移
    		maxv[S2[i]] = mx1;  //维护S2前缀最大值
    		mx1 = max(mx1, val[S2[i]]);   //下一个点
    	}
    	while(now < S1[0]){ //处理剩下的
    		mx2 = max(mx2, val[S1[now]]);
    		maxv[S1[++now]] = mx2;
    	}
    	maxf = ans, now = S1[0];
    	for(RG int i = S2[0]; i; --i){ //最大值在S1中的情况
    		while(now > top && maxv[S1[now]] >= maxv[S2[i]]){
    			maxf = max(maxf, f[S1[now]] - maxv[S1[now]]);
    			--now;
    		}
    		f[S2[i]] = max(f[S2[i]], maxf);
    	}
    	for(RG int i = 1; i <= S2[0]; ++i){ //更新到下一条链
    		f[S2[i]] += val[S2[i]];
    		S1[top + i] = S2[i];
    		id[S2[i]] = top + i;
    	}
    	S1[0] = top + S2[0];
    }
    
    int main(RG int argc, RG char* argv[]){
    	File("cut");
    	n = Input(), Fill(f, -127);
    	for(RG int i = 1, t; i <= n; ++i){
    		val[i] = Input(), t = Input();
    		for(RG int j = 1, tt; j <= t; ++j)
    			tt = Input(), edge[i].push_back(tt);
    	}
    	Dfs(1, 0);
    	for(RG int i = 1; i <= S1[0]; ++i) ans = max(ans, f[S1[i]]);
    	printf("%d
    ", ans);
        return 0;
    }
    
    
  • 相关阅读:
    twfont
    判断数组中某个元素的个数
    vue swiper中的大坑
    this指向问题
    vue.nextTick简单的用法
    类图解析
    设计模式
    设计模式
    Http Notes
    VS Notes
  • 原文地址:https://www.cnblogs.com/cjoieryl/p/8476899.html
Copyright © 2011-2022 走看看