【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 ...
随机推荐
- python爬虫 妹子图片网
代码如下 #coding=utf-8 import os import re import urllib from time import sleep import requests from lxm ...
- Vim新手节省时间的10多个小技巧
Vim新手节省时间的10多个小技巧 Vim 是很多开发者的首选编辑器,通过设置正确的命令和快捷方式,它可以帮你更快的完成工作.这篇文章我们为 Vim 新手提供一些快捷键等方面的小技巧,帮你提升工作效率 ...
- Filezilla 绿色版 禁止升级 能用。
FileZilla还是挺好用的,但是如果钟情于 绿色版的话,肯定首选是 免安装绿色版.但是呢,能找到的所谓的免升级 绿色版,都不能用.只要是打开软件了,就会在你还没有设置更新之前,就已经升级号了.并且 ...
- CSS设计指南之一 HTML标记与文档结构
HTML标记与文档结构 之所以从HTML讲起,是因为CSS的用途就是为HTML标记添加样式. 1.1 HTML标记基础 对于每个包含内容的元素,根据它所包含的内容是不是文本,有两种不同的方式给它们加标 ...
- leetcode 整理
1.Two Sum 构造Comparator,KSum 这一类的问题最基本的一题, 解法: 先sort,然后双指针,头尾各一个.进行加逼找值. 对于其余的KSum最终是降次到2次. 如3Sum固定一个 ...
- 查询MySQL某字段相同值得重复数据
1.先查询重复的id: SELECT book_id,COUNT(*) AS COUNT FROM xs_book_source WHERE site_id=5 GROUP BY book_id HA ...
- 动态include是通过servlet进行页面信息交互的
动态include是通过servlet进行页面信息交互的
- (转)python 搭建libsvm方法。python版本和libsvm版本匹配很重要!
<集体智慧编程>关于婚介数据集的SVM分类 转自:http://muilpin.blog.163.com/blog/static/165382936201131875249123/ 作 ...
- 【题解】CF#1012 C-Hill
感觉这题的状态还是比较明显的.设置状态 \(f[i][j][0/1]\) 表示dp到第 \(i\) 个位置,前面(包括这里)已经出现了 \(j\) 个山峰,当前位置是不是山峰即可 dp.这样的状态有一 ...
- BZOJ1854:[SCOI2010]连续攻击游戏——题解
http://www.lydsy.com/JudgeOnline/problem.php?id=1854 https://www.luogu.org/problemnew/show/P1640 lxh ...