【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 ...
随机推荐
- 发送tcp的时候,数据包是如何拷贝的
发送数据包的时候,用户态的数据包是如何拷贝到内核的kiovec msghd 结构体 icmp是走sock吗? 每一个skb_buffer的大小都是固定的吗?所以有skb_available这样的函数 ...
- [计算机网络-应用层] HTTP协议
1.HTTP概况 Web的应用层协议是超文本传输协议(HTTP),它是Web的核心. HTTP由两部分程序实现:一个客户机程序和一个服务器程序,它们运行在不同的端系统中,通过交换HTTP报文进行对话. ...
- Delphi实现在数据库中存取图像
向窗体上添加一个TListBox组件.一个TImage组件和一个TTable组件,设计完成的主界面如图1所示. 图1 主界面 本系统中需要设计一个新的基于Paradox 7的数据库Image.db,图 ...
- BZOJ 1797 最小割(最小割割边唯一性判定)
问题一:是否存在一个最小代价路径切断方案,其中该道路被切断? 问题二:是否对任何一个最小代价路径切断方案,都有该道路被切断? 现在请你回答这两个问题. 最小割唯一性判定 jcvb: 在残余网络上跑ta ...
- bzoj4501 旅行
题面: 小C来到了F国,小C想好好地参观F国.F国可以看一个有n个点m条边的有向无环图,小C刚开始站在1号点.假设现在小C站在x号点: 1.点x没有出边,结束旅游. 2.点x有o条出边,小C等概率地选 ...
- bzoj 1797: [Ahoi2009]Mincut 最小割 (网络流)
太神了直接看了hzwer的题解,有个新认识,一条路径上满流的一定是这条路径上所有边的最小值. type arr=record toward,next,cap,from:longint; end; co ...
- BZOJ5290 & 洛谷4438:[HNOI/AHOI2018]道路——题解
https://www.lydsy.com/JudgeOnline/problem.php?id=5290 https://www.luogu.org/problemnew/show/P4438 的确 ...
- BZOJ1912 APIO2010 洛谷P3629 巡逻
Description: 在一个地区中有 n 个村庄,编号为 1, 2, ..., n.有 n – 1 条道路连接着这些村 庄,每条道路刚好连接两个村庄,从任何一个村庄,都可以通过这些道路到达其 他任 ...
- 几个与特殊字符处理有关的PHP函数(过滤html js 标签)
函数名 释义 介绍 htmlspecialchars 将与.单双引号.大于和小于号化成HTML格式 &转成&"转成"' 转成'<转成<>转成> ...
- 直通BAT面试算法精讲课1
1.有一棵二叉树,请设计一个算法,按照层次打印这棵二叉树. 给定二叉树的根结点root,请返回打印结果,结果按照每一层一个数组进行储存,所有数组的顺序按照层数从上往下,且每一层的数组内元素按照从左往右 ...