Codeforces 1606F - Tree Queries(虚树+树形 dp)
显然我们选择删除的点连同 \(u\) 会形成一个连通块,否则我们如果选择不删除不与 \(u\) 在同一连通块中的点,答案一定更优。
注意到如果我们选择删除 \(u\) 的某个儿子 \(v\),那么答案的增量为 \(chd_v-1-k\),其中 \(chd_v\) 为节点 \(v\) 儿子的个数。而初始时刻答案为 \(chd_u\) 是个定值,因此我们的任务可以等效于,给每个点赋上一个点权 \(chd_u-1-k\),然后要找到一个以 \(u\) 为根的树上连通块,使得这个连通块中除去点 \(u\) 之外其他点点权之和尽可能大。
因此我们有了一个复杂度 \(\Theta(n^2)\) 的做法:对于每一个 \(k\) 都跑一遍树形 \(dp\),即设 \(dp_u\) 表示以 \(u\) 为根的连通块点权之和的最大值,那么显然有转移 \(dp_u=chd_u-1-k+\sum\limits_{v\in son_u}\max(dp_v,0)\)。注意到我们选出的树上连通块边界上(也就是所有满足 \(x\) 在树上连通块中,但 \(x\) 的所有儿子都不在树上连通块)中的点的点权必定都是正的,否则我们扣掉那些点权非正且在连通块边界上的点,答案肯定变得更优。因此考虑对于每个 \(k\) 将所有点权为正的点拎出来建一棵虚树——由于 \(\sum\limits_{i=1}^nchd_i=n-1\),所以对于所有 \(k\),点权为正的点的总个数是 \(\Theta(n)\) 的,然后对它们跑树形 \(dp\),然后每次查询一个点 \(u\) 为根的连通块点权之和的最大值时,如果点 \(u\) 本身就在虚树上,直接返回 \(u\) 的 DP 值即可,否则我们找到 \(u\) 在虚树上所在的链下方的节点 \(v\)——这个可以拿个 set
存储所有在虚树上的节点的 DFS 序,然后直接在 set
中 lower_bound
。那么以 \(u\) 为根的连通块点权和的最大值就是 \(dp_v\) 加上 \(fa_v\to u\) 这段路径和的点权和。
时间复杂度 \(\Theta(n\log n)\)。
const int MAXN=2e5;
const int LOG_N=18;
int n,qu,hd[MAXN+5],to[MAXN*2+5],nxt[MAXN*2+5],ec=0;
void adde(int u,int v){to[++ec]=v;nxt[ec]=hd[u];hd[u]=ec;}
int chd[MAXN+5],dep[MAXN+5],fa[MAXN+5][LOG_N+2];
int dfn[MAXN+5],tim=0,rid[MAXN+5],edt[MAXN+5];
void dfs0(int x,int f){
fa[x][0]=f;rid[dfn[x]=++tim]=x;
for(int e=hd[x];e;e=nxt[e]){
int y=to[e];if(y==f) continue;
chd[x]++;dep[y]=dep[x]+1;dfs0(y,x);
} edt[x]=tim;
}
int sum_chd[MAXN+5];
void dfs_chd(int x,int f){
for(int e=hd[x];e;e=nxt[e]){
int y=to[e];if(y==f) continue;
sum_chd[y]=sum_chd[x]+chd[y];
dfs_chd(y,x);
}
}
void lca_init(){
dep[1]=1;dfs0(1,0);
for(int i=1;i<=LOG_N;i++) for(int j=1;j<=n;j++)
fa[j][i]=fa[fa[j][i-1]][i-1];
}
int getlca(int x,int y){
if(dep[x]<dep[y]) swap(x,y);
for(int i=LOG_N;~i;i--) if(dep[x]-(1<<i)>=dep[y]) x=fa[x][i];
if(x==y) return x;
for(int i=LOG_N;~i;i--) if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
return fa[x][0];
}
vector<int> pos[MAXN+5];
int stk[MAXN+5],tp=0;set<int> st;
vector<pii> qv[MAXN+5];
ll calc_sum(int u,int v,int k){//u is ancestor of v
return (sum_chd[v]-sum_chd[u])-1ll*(k+1)*(dep[v]-dep[u]);
}
int calc_val(int u,int k){return chd[u]-1-k;}
vector<int> g[MAXN+5];
ll dp[MAXN+5],res[MAXN+5];
void insert(int x){
if(!tp) return stk[++tp]=x,void();
int lc=getlca(x,stk[tp]);
// printf("LCA of %d %d is %d\n",x,stk[tp],lc);
// printf("stack: ");
// for(int i=1;i<=tp;i++) printf("%d%c",stk[i]," \n"[i==tp]);
while(tp>1&&dep[stk[tp-1]]>dep[lc]){
// printf("adde %d %d\n",stk[tp-1],lc);
g[stk[tp-1]].pb(stk[tp]);--tp;
}
if(tp&&dep[stk[tp]]>dep[lc]){
// printf("adde %d %d\n",lc,stk[tp]);
g[lc].pb(stk[tp--]);
}
if(!tp||stk[tp]!=lc) stk[++tp]=lc;
stk[++tp]=x;
}
void fin(){
while(tp>=2){
// printf("adde %d %d\n",stk[tp-1],stk[tp]);
g[stk[tp-1]].pb(stk[tp]);--tp;
} tp=0;
}
void dfs_dp(int x,int k){
dp[x]=calc_val(x,k);st.insert(dfn[x]);
for(int y:g[x]){
dfs_dp(y,k);
dp[x]+=max(dp[y]+calc_sum(x,y,k)-calc_val(y,k),0ll);
// printf("calc_sum %d %d %d = %lld\n",x,y,k,calc_sum(x,y,k));
} //printf("DP %d %lld\n",x,dp[x]);
}
void clr(int x){for(int y:g[x]) clr(y);g[x].clear();}
int main(){
scanf("%d",&n);
for(int i=1,u,v;i<n;i++) scanf("%d%d",&u,&v),adde(u,v),adde(v,u);
lca_init();sum_chd[1]=chd[1];dfs_chd(1,0);scanf("%d",&qu);
// for(int i=1;i<=n;i++) printf("chd[%d]=%d\n",i,chd[i]);
for(int i=1;i<=n;i++) for(int j=0;j<chd[i];j++) pos[j].pb(i);
for(int i=1,u,k;i<=qu;i++) scanf("%d%d",&u,&k),qv[k].pb(mp(u,i));
for(int i=0;i<=MAXN;i++){
st.clear();
if(!pos[i].empty()){
// printf("solving %d\n",i);
sort(pos[i].begin(),pos[i].end(),[&](int x,int y){return dfn[x]<dfn[y];});
if(pos[i][0]!=1) insert(1);
for(int x:pos[i]) insert(x);
fin();dfs_dp(1,i);
}
for(pii p:qv[i]){
int u=p.fi,id=p.se;
set<int>::iterator it=st.lower_bound(dfn[u]);
if(it==st.end()||(*it)>edt[u]) res[id]=chd[u];
else{
int pt=rid[*it];
// printf("%d %d\n",id,pt);
// printf("%lld\n",calc_sum(fa[u][0],fa[pt][0],i));
res[id]=chd[u]+max(0ll,dp[pt]+calc_sum(fa[u][0],fa[pt][0],i)-calc_val(u,i));
}
}
clr(1);
}
for(int i=1;i<=qu;i++) printf("%lld\n",res[i]);
return 0;
}
/*
11
1 2
2 3
2 4
1 5
5 6
5 7
7 8
7 9
7 10
1 11
4
1 0
1 1
5 2
11 0
*/
Codeforces 1606F - Tree Queries(虚树+树形 dp)的更多相关文章
- 【BZOJ-3572】世界树 虚树 + 树形DP
3572: [Hnoi2014]世界树 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 1084 Solved: 611[Submit][Status ...
- 【BZOJ-2286】消耗战 虚树 + 树形DP
2286: [Sdoi2011消耗战 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 2120 Solved: 752[Submit][Status] ...
- bzoj 2286(虚树+树形dp) 虚树模板
树链求并又不会写,学了一发虚树,再也不虚啦~ 2286: [Sdoi2011]消耗战 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 5002 Sol ...
- BZOJ_2286_[Sdoi2011]消耗战_虚树+树形DP+树剖lca
BZOJ_2286_[Sdoi2011]消耗战_虚树+树形DP Description 在一场战争中,战场由n个岛屿和n-1个桥梁组成,保证每两个岛屿间有且仅有一条路径可达.现在,我军已经侦查到敌军的 ...
- BZOJ5341[Ctsc2018]暴力写挂——边分治+虚树+树形DP
题目链接: CSTC2018暴力写挂 题目大意:给出n个点结构不同的两棵树,边有边权(有负权边及0边),要求找到一个点对(a,b)满足dep(a)+dep(b)-dep(lca)-dep'(lca)最 ...
- [WC2018]通道——边分治+虚树+树形DP
题目链接: [WC2018]通道 题目大意:给出三棵n个节点结构不同的树,边有边权,要求找出一个点对(a,b)使三棵树上这两点的路径权值和最大,一条路径权值为路径上所有边的边权和. 我们按照部分分逐个 ...
- 2018.09.25 bzoj3572: [Hnoi2014]世界树(虚树+树形dp)
传送门 虚树入门题? 好难啊. 在学习别人的写法之后终于过了. 这道题dp方程很好想. 主要是不好写. 简要说说思路吧. 显然最优值只能够从子树和父亲转移过来. 于是我们先dfs一遍用儿子更新父亲,然 ...
- CodeCraft-19 and Codeforces Round #537 (Div. 2) E 虚树 + 树形dp(新坑)
https://codeforces.com/contest/1111/problem/E 题意 一颗有n个点的树,有q个询问,每次从树挑出k个点,问将这k个点分成m组,需要保证在同一组中不存在一个点 ...
- Codeforces 1111 E. Tree(虚树,DP)
题意 有一棵树,q个询问,每次询问,指定一个点做树根,再给定k个点,要求把这些点分成不超过m组的方案数,分配的限制是任意两个有祖先关系的点不能分在同一组.题目还保证了所有的询问的k加起来不超过1e5. ...
随机推荐
- Python技法3:匿名函数、回调函数和高阶函数
1.定义匿名或内联函数 如果我们想提供一个短小的回调函数供sort()这样的函数用,但不想用def这样的语句编写一个单行的函数,我们可以借助lambda表达式来编写"内联"式的函数 ...
- QG-2019-AAAI-Improving Neural Question Generation using Answer Separation
Improving Neural Question Generation using Answer Separation 本篇是2019年发表在AAAI上的一篇文章.该文章在基础的seq2seq模型的 ...
- relativeLayout相对布局的嵌套在py中的引用
from kivy.app import App from kivy.uix.button import Button from kivy.uix.relativelayout import Rela ...
- 热身 for computer industry
项目 内容 作业属于 班级博客 作业要求 作业要求 个人课程目标 掌握软件工程基础知识 具体有助方面 个人认知与规划 其他参考文献 博客Ⅰ 博客 Ⅱ 选择计算机 你为什么选择计算机专业?你认为你的条件 ...
- 2021.9.28考试总结[NOIP模拟64]
T1 三元组 发现确定\(b,c\)的情况下,\(a\)的值域是连续的.确定\(b\)后\(a+b\)的取值是\([1+b,b+b]\).树状数组维护对每个\(b\)可行的\(c\). 注意取模后取值 ...
- 按照工业标准1英寸=25.4mm,而在电子元件成像领域Sensor尺寸1英寸=16mm。
按照工业标准1英寸=25.4mm,而在电子元件成像领域Sensor尺寸1英寸=16mm. 我们平常所说的CCD/CMOS的尺寸,实际上是指Sensor对角线的长度,这一点跟我们平常所说的屏幕尺寸是一样 ...
- stm32看门狗详细解答,看了觉得一下子明白了很多
一.独立看门狗 STM32 的独立看门狗由内部专门的 40Khz 低速时钟驱动,即使主时钟发生故障,它也仍然有效. 看门狗的原理:单片机系统在外界的干扰下会出现程序跑飞的现象导致出现死循环,看门狗电路 ...
- 绘制PCB电路原理图的8种方法
1.选择集成电路,变压器,晶体管等组件,这些组件体积庞大,有许多引脚并在电路中起主要作用,然后从选定的参考引脚中抽取,以减少错误. 2.如果PCB上标有元件编号(如VD870,R330,C466等), ...
- GDI+图形图像技术1
System.Drawing命名空间提供了对GDI+基本图形功能的访问,其中一些子命名空间中提供了更高级的功能. GDI+由GDI发展而来,是Windows图形显示程序与实际物理设备之间的桥梁. GD ...
- 释放 cached 内存
巡检服务器发现内存可用很少了 top 命令查看是没有占用大内存的进程,cached特别大,释放cached就可以了 可用内存= free + buffers + cached 以下方法可以释放cach ...