【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 ...
随机推荐
- C++多态实现与继承
面向对象的三个基本特征 面向对象的三个基本特征是:封装.继承.多态.其中, 封装可以隐藏实现细节,使得代码模块化: 继承可以扩展已存在的代码模块(类),它们的目的都是为了——代码重用: 而多态则是为了 ...
- 当重写了 httpservlet重写了GenericServlet的init方法时候 必须显示调用GenericServlet的init方法时候 才能在别的方法(父类创建config实例) 例如 doget里面使用servletContext对象 不重写init 则可以直接使用
- Properties 的list方法 直接将内容放到文本中
Properties 的list方法 直接将内容放到文本中
- Go语言【第十二篇】:Go数据结构之:切片(Slice)、范围(Range)、集合(Map)
Go语言切片(Slice) Go语言切片是对数组的抽象,Go数组的长度不可改变,在特定场景中这样的集合就不太适用,Go中提供了一种灵活,功能强悍的内置类型切片("动态数组"),与数 ...
- P2420 让我们异或吧
题目描述 异或是一种神奇的运算,大部分人把它总结成不进位加法. 在生活中…xor运算也很常见.比如,对于一个问题的回答,是为1,否为0.那么: (A是否是男生 )xor( B是否是男生)=A和B是否能 ...
- Javascript-基础1
1,变量: name="alex" #默认是全局变量 var name="eric" #局部变量 2. 写JS代码:---html中写,---临时文件可以写在 ...
- Android SDK Manager下载,解决方案
一.Windows 平台 在C:\Windows\System32\drivers\etc\hosts文件.添加一行:74.125.237.1 dl-ssl.google.com 二.Li ...
- BZOJ1911:[Apio2010]特别行动队——题解
http://www.lydsy.com/JudgeOnline/problem.php?id=1911 又是一个显然的dp……好吧我懒得讲了. s[i]是战斗力前缀和. 我们仍然设k<j< ...
- BZOJ 1085 [SCOI2005]骑士精神 【A*启发式搜索】
1085: [SCOI2005]骑士精神 Time Limit: 10 Sec Memory Limit: 162 MB Submit: 2838 Solved: 1663 [Submit][St ...
- HDOJ.2084 数塔(DP)
数塔 点我挑战题目 题意分析 DP的思想,自上而下计算. [这几天比较忙 有空补上] 代码总览 /* Title:HDOJ.2084 Author:pengwill Date:2017-1-14 */ ...