【HNOI】 攻城略池 tree-dp
【题目大意】
给定一棵树,边有边权,每个节点有一些兵,现在叶子节点在0时刻被占领,并且任意节点在x被占领,那么从x+1开始,每单位时间产生一个兵,兵会顺着父亲节点一直走到根(1),其中每经过一个节点,该节点的兵储量减少1,问所有节点都被攻陷的最晚时间。
【数据范围】
n<=10^5.
首先我们可以设每个节点被攻占的时间为w[i],那么对于一个父节点x,我们可以二分一个答案,来判断这个答案是否合法,那么假设我们分到的值为time,那么对于x子树中所有的节点p,每个节点的贡献为max(0,time-w[p]-d[x][p])。那么我们只需要判断贡献和与x节点的兵的数量就可以了。
那么对于一个点,我们可以用一颗平衡树来存这个点为根节点的子树中所有节点的w[p]+d[x][p]值,那么对于一个二分到的答案,我们只需要判断树中小于time的和,再用time*size减去就好了。对于一个节点,我们只需要启发式合并他所有的子节点的平衡树就好了。
反思:开始写的时候没看long long,结果发现连第二个测试点都过不去,然后开了之后就出了各种各样的问题,开始是return 0没有改成return 1LL,后来发现平衡树中维护的sum值有的时候没有被更新,我是在插入和删除的时候修改的这个,和size一起修改,也不知道哪儿错了,后来就直接在询问的时候维护sum,然后还是不行,后来能加上的地方都加上了才过了。。。。
//By BLADEVIL
#include <cstdio>
#include <algorithm>
#define maxn 100010
#define LL long long using namespace std; LL n,l,tot,save;
LL a[maxn],pre[maxn<<],other[maxn<<],last[maxn],len[maxn<<];
LL w[maxn],flag[maxn],que[maxn],dis[maxn],rot[maxn];
LL left[maxn<<],right[maxn<<],key[maxn<<],size[maxn<<],sum[maxn<<]; void connect(LL x,LL y,LL z) {
pre[++l]=last[x];
last[x]=l;
other[l]=y;
len[l]=z;
} void left_rotate(LL &t) {
LL k=right[t];
right[t]=left[k];
left[k]=t;
size[k]=size[t];
sum[k]=sum[t];
size[t]=size[left[t]]+size[right[t]]+1LL;
sum[t]=sum[left[t]]+sum[right[t]]+key[t];
t=k;
} void right_rotate(LL &t) {
LL k=left[t];
left[t]=right[k];
right[k]=t;
size[k]=size[t];
sum[k]=sum[t];
size[t]=size[left[t]]+size[right[t]]+1LL;
sum[t]=sum[left[t]]+sum[right[t]]+key[t];
t=k;
} void maintain(LL &t,int flag) {
if (!flag) {
if (size[left[left[t]]]>size[right[t]])
right_rotate(t); else
if (size[right[left[t]]]>size[right[t]])
left_rotate(left[t]),right_rotate(t); else return ;
} else {
if (size[right[right[t]]]>size[left[t]])
left_rotate(t); else
if (size[left[right[t]]]>size[left[t]])
right_rotate(right[t]),left_rotate(t); else return ;
}
maintain(left[t],); maintain(right[t],);
maintain(t,); maintain(t,);
//sum[t]=sum[left[t]]+sum[right[t]]+key[t];
} void t_insert(LL &t,LL v) {
if (!t) {
t=++tot;
left[t]=right[t]=0LL;
size[t]=1LL;
key[t]=sum[t]=v;
} else {
size[t]++; sum[t]+=v;
if (v<key[t]) t_insert(left[t],v); else t_insert(right[t],v);
maintain(t,v>=key[t]);
}
}
/*
LL t_delete(LL &t,LL v) {
size[t]--;
if ((v==key[t])||((v>key[t])&&(!right[t]))||((v<key[t])&&(!left[t]))) {
save=key[t];
if ((!left[t])||(!right[t]))
t=left[t]+right[t]; else key[t]=t_delete(left[t],v+1LL);
} else {
if (v<key[t]) return t_delete(left[t],v); else return t_delete(right[t],v);
}
sum[t]=sum[left[t]]+sum[right[t]]+key[t];
return save;
}
*/ LL t_delete(LL &t,LL v) {
if ((v==key[t])||((v>key[t])&&(!right[t]))||((v<key[t])&&(!left[t]))) {
save=key[t];
if ((!left[t])||(!right[t])) {
t=left[t]+right[t];
sum[t]=sum[left[t]]+sum[right[t]]+key[t];
}else key[t]=t_delete(left[t],v+1LL);
//tmp = key[t];
} else {
if (v<key[t]) save = t_delete(left[t],v); else save = t_delete(right[t],v);
}
//size[t]=size[left[t]]+size[right[t]]+1;
sum[t]=sum[left[t]]+sum[right[t]]+key[t];
return save;
} void combine(LL &t1,LL &flag1,LL t2,LL flag2) {
if (size[t1]<size[t2]) swap(t1,t2),swap(flag1,flag2);
while (t2) {
t_insert(t1,key[t2]+flag2-flag1);
t_delete(t2,key[t2]);
}
} LL judge(LL t,LL time){
sum[t]=sum[left[t]]+sum[right[t]]+key[t];
if (!t) return 0LL;
if (key[t]<=time)
return judge(right[t],time)+(size[left[t]]+1LL)*time-sum[left[t]]-key[t]; else
return judge(left[t],time);
} void work() {
LL h=0LL,t=1LL;
que[]=1LL; dis[]=1LL;
while (h<t) {
LL cur=que[++h];
for (LL p=last[cur];p;p=pre[p]) {
if (dis[other[p]]) continue;
que[++t]=other[p];
dis[other[p]]=dis[cur]+1LL;
}
}
//for (LL i=1;i<=n;i++) printf("%d ",que[i]); printf("\n");
for (LL i=n;i;i--) {
LL cur=que[i];
for (LL p=last[cur];p;p=pre[p]) {
if (dis[other[p]]<dis[cur]) continue;
combine(rot[cur],flag[cur],rot[other[p]],flag[other[p]]+len[p]);
}
if ((!rot[cur])||(!a[cur])) {
t_insert(rot[cur],-flag[cur]);
//printf("%lld %lld %lld\n",cur,rot[cur],flag[cur]);
//for (LL i=1;i<=20;i++) printf("%lld %lld %lld %lld %lld %lld\n",i,left[i],right[i],size[i],key[i],sum[i]);
continue;
}
//printf("%lld %lld %lld\n",cur,rot[cur],flag[cur]);
//for (LL i=1;i<=20;i++) printf("%lld %lld %lld %lld %lld %lld\n",i,left[i],right[i],size[i],key[i],sum[i]);
LL l=1LL,r=1LL<<,mid,ans;
while (l<=r) {
//printf("%d %d\n",l,r);
mid=l+r>>1LL;
//if (cur==1) printf("%lld %lld\n",l,r);
if (judge(rot[cur],mid-flag[cur])>=a[cur]) r=mid-1LL,ans=mid; else l=mid+1LL;
}
w[cur]=ans;
//if (cur==1) printf("|%lld\n",judge(rot[cur],-6));
t_insert(rot[cur],w[cur]-flag[cur]);
//printf("%lld %lld %lld\n",cur,rot[cur],flag[cur]);
//for (LL i=1;i<=20;i++) printf("%lld %lld %lld %lld %lld %lld\n",i,left[i],right[i],size[i],key[i],sum[i]);
}
//printf("%lld %lld\n",rot[1],flag[1]);
//for (LL i=1;i<=20;i++) printf("%lld %lld %lld %lld %lld %lld\n",i,left[i],right[i],size[i],key[i],sum[i]);
//for (LL i=1;i<=n;i++) printf("%lld ",w[i]); printf("\n");
LL ans=0LL;
for (int i=;i<=n;i++) ans=max(ans,w[i]);
printf("%lld\n",ans);
} void check() {
LL t1=,t2=,flag1=,flag2=;
for (LL i=;i<=;i++) t_insert(t1,i),t_insert(t2,i); t_insert(t2,);
combine(t1,flag1,t2,flag2);
printf("%lld\n",t1);
for (LL i=;i<=;i++) printf("%ld %lld %lld %lld %lld %lld\n",i,left[i],right[i],size[i],key[i],sum[i]);
return ;
LL t=;
for (LL i=;i<=;i++) t_insert(t,i);
t_delete(t,); printf("%lld\n",t);
for (LL i=;i<=;i++) printf("%lld %lld %lld %lld %lld %lld\n",i,left[i],right[i],size[i],key[i],sum[i]);
printf("%lld\n",judge(t,));
} int main() {
//check(); return 0;
freopen("conquer.in","r",stdin); freopen("conquer.out","w",stdout);
scanf("%lld",&n);
for (LL i=;i<=n;i++) scanf("%lld",&a[i]);
for (LL i=;i<n;i++) {
LL x,y,z; scanf("%lld%lld%lld",&x,&y,&z);
connect(x,y,z); connect(y,x,z);
}
work();
fclose(stdin); fclose(stdout);
return ;
}
【HNOI】 攻城略池 tree-dp的更多相关文章
- YbtOJ#763-攻城略池【线段树合并】
正题 题目链接:http://www.ybtoj.com.cn/problem/763 题目大意 给出\(n\)个点的一棵树,每个\(d_i=0\)的点每秒会产生一个士兵往根节点走,走到一个节点让一个 ...
- 软件攻城狮究级装B指南
引言 装B于无形,随性而动,顺道而行,待霸业功成之时,你会发现:装B是牛B最好的的试金石. -- SuperDo 第一章.人间兵器(准备工具) <论语·魏灵公>:“工欲善其事,必先利其器. ...
- 2015Web前端攻城之路
2015目标成为一名合格的前端攻城狮. 养成计划: 1.html / css 2.js 3.ajax 4.框架 5.项目实战
- 安全攻城狮研发技能栈V1.0,附详细点评~
2015-12-21 正宗好PT 正宗好PT 今天公司年会,又木有抽到奖,求安慰/(ㄒoㄒ)/~~ 言归正传,我曾经在推特发过一个Skill CheatSheet,被转发和点赞了几百次,我又更新了一下 ...
- Android优秀资源整理合集(论菜鸟到高级攻城狮)
转载请注明转自:http://blog.csdn.net/u011176685/article/details/51434702 csdn文章:Android优秀资源整理合集(论菜鸟到高级攻城狮) 时 ...
- JBPM4之decision节点:3、程序猿|菜鸟|攻城狮|牛人
JBPM入门系列文章: JBPM4入门——1.jbpm简要介绍 JBPM4入门——2.在eclipse中安装绘制jbpm流程图的插件 JBPM4入门——3.JBPM4开发环境的搭建 JBPM4入门—— ...
- 攻城狮送女友的CSS3生日蛋糕
在线预览:http://keleyi.com/keleyi/phtml/html5/29.htm 代码如下: <!DOCTYPE html> <html> <head&g ...
- 遗留系统:IT攻城狮永远的痛
我常常觉得我们非常幸运,我们现在所处的时代是一个令人振奋的时代,我们进入了软件工业时代.在这个时代里,我们进行软件开发已经不再是一个一个的小作坊,我们在进行着集团化的大规模开发.我们开发的软件不再是为 ...
- 96. Unique Binary Search Trees (Tree; DP)
Given n, how many structurally unique BST's (binary search trees) that store values 1...n? For examp ...
随机推荐
- Redis的概述和简单使用(转载)
文章来源:http://jingyan.baidu.com/article/db55b60996d0124ba30a2f92.html Redis是一个基于key-value的高速缓存系统,类似于me ...
- RPC架构-美团,京东面试题目
RPC(Remote Procedure Call) RPC服务 从三个角度来介绍RPC服务:分别是RPC架构,同步异步调用以及流行的RPC框架. RPC架构 先说说RPC服务的基本架构吧.允许我可耻 ...
- [BinaryTree] 二叉树类的实现
二叉树结点的抽象数据类型: template<class T> class BinaryTreeNode { friend class BinaryTree<T>; priva ...
- 用js+css3做一个小球投篮的动画(easing)
<!DOCTYPE html> <html> <head> <script src="jquery-1.11.3.min.js">& ...
- BZOJ 1066 蜥蜴(网络流)
很普通的拆点网络流,把每个柱子拆成两个点(i,j,0)和(i,j,1).对于柱子的高度限制则加边((i,j,0),(i,j,1),height). 两个柱子能互相到达则加边((i,j,1),(i1,j ...
- 【bzoj1725】[USACO2006 Nov]Corn Fields牧场的安排 状态压缩dp
题目描述 Farmer John新买了一块长方形的牧场,这块牧场被划分成M列N行(1<=M<=12; 1<=N<=12),每一格都是一块正方形的土地.FJ打算在牧场上的某几格土 ...
- Linq里where出现null的问题
今天遇到一个问题,怎么在where里判断一个字段是否为null,并且这个字段不是字符串string类型,而是int和GUID类型,折腾了半天终于搞明白了.(由于项目是我半路接手的,问题是前期的同事给我 ...
- BZOJ2242:[SDOI2011]计算器——题解
https://www.lydsy.com/JudgeOnline/problem.php?id=2242 https://www.luogu.org/problemnew/show/P2485 你被 ...
- BZOJ1596 [Usaco2008 Jan]电话网络 【树形dp】
题目链接 BZOJ1596 题解 先抽成有根树 设\(f[i][0|1][0|1]\)表示以\(i\)为根,儿子都覆盖了,父亲是否覆盖,父亲是否建塔的最少建塔数 转移一下即可 #include< ...
- UVA.357 Let Me Count The Ways (DP 完全背包)
UVA.357 Let Me Count The Ways (DP 完全背包) 题意分析 与UVA.UVA.674 Coin Change是一模一样的题.需要注意的是,此题的数据量较大,dp数组需要使 ...