【HDOJ6662】Acesrc and Travel(树形DP,换根)

题意:有一棵n个点的树,每个点上有两个值a[i],b[i]

A和B在树上行动,A到达i能得到a[i]的偷税值,B能得到b[i],每次行动只能选择相邻的点作为目标

两个人都想最大化自己的偷税值和对方的差,都按最优策略行动,不能走已经走过的点,行动直到没有点可走为止

A可以选择任意出发点,然后B开始走,然后A开始走……

n<=1e5,0<=a[i],b[i]<=1e9

思路:

f[u][0]表示从u出发下一步走儿子的min,f[u][1]表示max

g[u][0]表示从u出发下一步走父亲的min,g[u][1]表示max

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 typedef long long ll;
  4 typedef unsigned int uint;
  5 typedef unsigned long long ull;
  6 typedef pair<int,int> PII;
  7 typedef pair<ll,ll> Pll;
  8 typedef vector<int> VI;
  9 typedef vector<PII> VII;
 10 //typedef pair<ll,ll>P;
 11 #define N  1000010
 12 #define M  200010
 13 #define fi first
 14 #define se second
 15 #define MP make_pair
 16 #define pb push_back
 17 #define pi acos(-1)
 18 #define mem(a,b) memset(a,b,sizeof(a))
 19 #define rep(i,a,b) for(int i=(int)a;i<=(int)b;i++)
 20 #define per(i,a,b) for(int i=(int)a;i>=(int)b;i--)
 21 #define lowbit(x) x&(-x)
 22 #define Rand (rand()*(1<<16)+rand())
 23 #define id(x) ((x)<=B?(x):m-n/(x)+1)
 24 #define ls p<<1
 25 #define rs p<<1|1
 26
 27 const int MOD=1e9+7,inv2=(MOD+1)/2;
 28       double eps=1e-4;
 29       int INF=1e9;
 30       int inf=0x7fffffff;
 31       int dx[4]={-1,1,0,0};
 32       int dy[4]={0,0,-1,1};
 33
 34 ll f[N][2],g[N][2];
 35 ll t1[N],t2[N],t3[N],t4[N],t5[N],t6[N],a[N],b[N];
 36 int head[N],vet[N],nxt[N],d[N],tot;
 37
 38
 39 int read()
 40 {
 41    int v=0,f=1;
 42    char c=getchar();
 43    while(c<48||57<c) {if(c==‘-‘) f=-1; c=getchar();}
 44    while(48<=c&&c<=57) v=(v<<3)+v+v+c-48,c=getchar();
 45    return v*f;
 46 }
 47
 48 void add(int a,int b)
 49 {
 50     nxt[++tot]=head[a];
 51     vet[tot]=b;
 52     head[a]=tot;
 53 }
 54
 55 void dfs1(int u,int fa)
 56 {
 57     int e=head[u],s=0;
 58     ll t1=INF,t2=-INF;
 59     while(e)
 60     {
 61         int v=vet[e];
 62         if(v!=fa)
 63         {
 64             s++;
 65             dfs1(v,u);
 66             t1=min(t1,f[v][1]);
 67             t2=max(t2,f[v][0]);
 68         }
 69         e=nxt[e];
 70     }
 71     if(s)
 72     {
 73         f[u][0]=t1+a[u]-b[u];
 74         f[u][1]=t2+a[u]-b[u];
 75     }
 76      else f[u][0]=f[u][1]=a[u]-b[u];
 77 }
 78
 79 void dfs2(int u,int fa)
 80 {
 81     int s=0;
 82     int e=head[u];
 83     while(e)
 84     {
 85         int v=vet[e];
 86         if(v!=fa)
 87         {
 88             s++;
 89             t1[s]=f[v][0];
 90             t2[s]=f[v][1];
 91         }
 92         e=nxt[e];
 93     }
 94     t3[1]=t1[1];
 95     rep(i,2,s) t3[i]=max(t3[i-1],t1[i]);
 96     t4[s]=t1[s];
 97     per(i,s-1,1) t4[i]=max(t4[i+1],t1[i]);
 98     t5[1]=t2[1];
 99     rep(i,2,s) t5[i]=min(t5[i-1],t2[i]);
100     t6[s]=t2[s];
101     per(i,s-1,1) t6[i]=min(t6[i+1],t2[i]);
102     e=head[u];
103     int i=0;
104     while(e)
105     {
106         int v=vet[e];
107         if(v!=fa)
108         {
109             i++;
110             ll t=g[u][1];
111             ll t0=-INF;
112             if(i-1>=1) t0=max(t0,t3[i-1]+a[u]-b[u]);
113             if(i+1<=s) t0=max(t0,t4[i+1]+a[u]-b[u]);
114             if(u==1&&s>1) t=t0;
115              else t=max(t,t0);
116             g[v][0]=a[v]-b[v]+t;
117             t=g[u][0];
118             t0=INF;
119             if(i-1>=1) t0=min(t0,t5[i-1]+a[u]-b[u]);
120             if(i+1<=s) t0=min(t0,t6[i+1]+a[u]-b[u]);
121             if(u==1&&s>1) t=t0;
122              else t=min(t,t0);
123             g[v][1]=a[v]-b[v]+t;
124         }
125         e=nxt[e];
126     }
127     e=head[u];
128     while(e)
129     {
130         int v=vet[e];
131         if(v!=fa) dfs2(v,u);
132         e=nxt[e];
133     }
134 }
135
136
137 int main()
138 {
139     //freopen("1.in","r",stdin);
140     int cas;
141     scanf("%d",&cas);
142     while(cas--)
143     {
144         int n=read();
145         rep(i,1,n) a[i]=read();
146         rep(i,1,n) b[i]=read();
147         rep(i,1,n) head[i]=d[i]=0;
148         tot=0;
149         rep(i,1,n-1)
150         {
151             int x=read(),y=read();
152             add(x,y);
153             add(y,x);
154             d[x]++; d[y]++;
155         }
156         dfs1(1,0);
157         g[1][0]=g[1][1]=a[1]-b[1];
158         dfs2(1,0);
159         ll ans=-INF;
160         rep(i,1,n)
161         {
162             if(i==1) ans=max(ans,f[i][0]);
163              else if(d[i]==1) ans=max(ans,g[i][0]);
164               else ans=max(ans,min(f[i][0],g[i][0]));
165         }
166         printf("%I64d\n",ans);
167
168     }
169
170     return 0;
171 }

原文地址:https://www.cnblogs.com/myx12345/p/11655728.html

时间: 2024-07-30 22:11:03

【HDOJ6662】Acesrc and Travel(树形DP,换根)的相关文章

寒武纪-1005 Travel(树形DP)

一.题目链接 http://aiiage.hustoj.com/problem.php?id=1005 二.题面 PDF:http://aiiage.hustoj.com/upload/file/20180114/20180114145400_75397.pdf 三.思路 正赛时,我一开始写了个感觉在O(N*N*k)的时间复杂度内做了优化的代码,交上去,TLE.尝试了各种可能的情况,还是TLE.赛后,看了官方题解.如下: 然而,2.3的“相对直观的想法”,实在是没想到一个时间复杂度在O(N*k*

cf219d 基础换根法

/*树形dp换根法*/ #include<bits/stdc++.h> using namespace std; #define maxn 200005 struct Edge{int to,nxt,flag;}edge[maxn<<1]; int root,n,s,t,head[maxn],tot,dp[maxn]; void init(){ memset(head,-1,sizeof head); tot=0; } void addedge(int u,int v,int fl

题解 poj3585 Accumulation Degree (树形dp)(二次扫描和换根法)

写一篇题解,以纪念调了一个小时的经历(就是因为边的数组没有乘2 phhhh QAQ) 题目 题目大意:找一个点使得从这个点出发作为源点,流出的流量最大,输出这个最大的流量. 以这道题来介绍二次扫描和换根法 作为一道不定根的树形DP,如果直接对每个点进行DP,可能时间会炸掉 但是,优秀的二次换根和扫描法可以再O(n^2)内解决问题. 二次扫描的含义:(来自lyd 算法竞赛进阶指南) 第一次扫描:任选一个节点为根节点(我会选1)在树上进行树形DP,在回溯时,从儿子节点向父节点(从底向上)进行状态转移

肥宅快乐树 换根+树形DP/dfs

肥宅快乐树是一棵神秘而巨大的树,它长有许多枝条和节点,每条枝连接树中两个节点,每个节点上都长有一瓶肥宅快乐水. 何老板是肥宅快乐水的资深爱好者.历经艰难,他终于找到了这棵传说中的快乐树.他想要获取树上所有的快乐水,迫不及待地想从树根往树上爬. 每经过一条树枝都会耗费一定体力.而且快乐树自带防御功能,即每条枝上都有一个一次性陷阱,一旦踏上该枝,何老板就会被立即弹射回地面,他得重新从根往上爬. (注1:一次性陷阱是指,陷阱只在第一次经过该枝时有效) (注2:从i号点回到i的父亲节点,不耗费体力) 每

换根DP

换根dp的通法:1.第一次扫描时,任选一个点为根,在"有根树"上执行一次树形DP,也就在回溯时发生的,自底向上的状态转移. 2.第二次扫描时,从刚才选出的根出发,对整棵树执行一次dfs,在每次递归前进行自上向下的推导,计算出换根后的解. 1.POJ3585 Accumulation Degree dp[i]以i为根的子树中,把i作为源点的最大流量 转移\(dp[x]=\sum_{y\epsilon son(x)}^{}\left\{\begin{matrix} min(dp[y],le

【换根dp】9.22小偷

换根都不会了 题目大意 给定一棵$n$个点的树和树上一撮关键点,求到所有$m$个关键点距离的最大值$dis_{max}\le LIM$的点的个数. $n,m\le 30000,LIM\le 30000$ 题目分析 考虑在求出一个点的情况下如何转移到其子节点. 对点$u$最直接关心的状态是$mx[u]$:所有关键点到$u$的最大距离. 对点$u$的子节点$v$来说,$u$能带给它的只是“外面的世界”——$v$子树的补集这块贡献,也就是对于$u$的除了$v$子树的$mx[u]$. 因为$mx[u]$

换根dp「小奇的仓库&#183;randomwalking&#183;」

把以前考试换根题集中写一下 随便选一个点做根一遍$dfs$求子树内贡献,再通过特殊手段算$ans[1]$,最后$dfs$求其他$ans$ 拆成子树内,子树外分别算贡献差,得儿子是很常见套路了 小奇的仓库 $M<=15$ 题解 很久之前做的换根dp,当时觉得真是神仙,现在看还是觉得很神仙 不同于一般换根dp,这个题$n^2$并不好写 所以$n^2$算法就省略了 考虑$M$非常小,可以计算$M$对答案影响 一个直接的想法是先算出来原答案,再减去现在答案 //本来为j现在异或M,变化了j-delta

poj3585 Accumulation Degree(换根dp)

传送门 换根dp板子题(板子型选手 题意: 一棵树确定源点和汇点找到最大的流量(拿出一整套最大瘤板子orz const int maxn=2e5+10; int head[maxn],tot; struct node { int nt,to;long long w; }q[2*maxn]; long long dp[maxn];int cnt[maxn]; void insert(int u,int v,long long w) { q[tot].nt=head[u];q[tot].w=w;q[

codeforces1156D 0-1-Tree 换根dp

题目传送门 题意: 给定一棵n个点的边权为0或1的树,一条合法的路径(x,y)(x≠y)满足,从x走到y,一旦经过边权为1的边,就不能再经过边权为0的边,求有多少边满足条件? 思路:设$f[u]$为以1为根,自下而上到$u$的末节点是1的合法路径数量,$g[u]$代表以1为根,自下而上到$v$末节点是0的合法路径数量,这个可以通过一遍dfs简单求解. 再设$nf[u]$和$ng[u]$代表以u为根的两种合法路径数量,进行换根dfs,在换根的过程中: 若某一条边是0边,则: $ng[st.to]=

HDU 2196 Computer 二次扫描与换根DP

题意:给定一棵树,求树上所有点到其最远点的距离. 数据范围: 1 <= N <= 100000 ------------------------------------------我是分割线------------------------------------------ 题解:对于每个节点u来说,其可能到达的最长距离为max{其子树内的最长距离,其父节点不经过u的子树内的最长距离}.于是,我们便可以在第一遍dfs中预处理节点x到其子树内的最长距离,顺带求一下次长距离,方便转移. // f[