[HDU4729]An Easy Problem for Elfness
[HDU4729]An Easy Problem for Elfness
题目大意:
给你一棵\(n(n\le10^5)\)个点的树,树上每条边都有容量。
\(m(m\le10^5)\)次询问,每次询问你有\(k\)的预算,可以花\(a\)的代价在任意两点间建一条流容量为\(1\)的边(包括重边),或者花费\(b\)的代价将某条边的容量加\(1\),问在不超过预算的情况下,从\(s\)到\(t\)的最大流量。
思路:
首先,考虑没有\(k,a,b\)的情况,答案就是\(s,t\)路径上的权值最小值\(min\)。
对于\(a\le b\)的情况,由于我们每在\(s\)和\(t\)之间新建一条边都能增加\(1\)的容量,则我们把所有的预算都用来新建边肯定是最优策略。答案是\(min+\lfloor\frac ka\rfloor\)。
对于\(a>b\)的情况,我们有以下两种可能最优的策略:
- 花费\(a\)的代价新建一条边,然后用剩下的所有预算扩充这条新边的容量。
- 不断将路径上最小边扩充\(1\)的容量。
对于第一种策略,我们不难得到答案就是\(min+1+\lfloor\frac{k-a}b\rfloor\)。
对于第二种策略,我们可以二分答案\(mid\)。设路径上边容量\(<mid\)的边数有\(c\)个,权值和为\(w\)。则\(c\times mid-w\)就是需要扩充的容量之和。若\(c\times mid-w\le\lfloor\frac kb\rfloor\),则\(ans>=mid\),反之\(ans<mid\)。
上文提及的边数与权值和可以用树上主席树方便地求得。
时间复杂度\(\mathcal O(n\log^2n)\)。
源代码:
#include<cstdio>
#include<cctype>
#include<climits>
#include<algorithm>
#include<forward_list>
inline int getint() {
register char ch;
while(!isdigit(ch=getchar()));
register int x=ch^'0';
while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
return x;
}
using int64=long long;
constexpr int N=1e5+1,logN=17,logW=15,W=10000;
using Edge=std::pair<int,int>;
std::forward_list<Edge> e[N];
inline void add_edge(const int &u,const int &v,const int &w) {
e[u].emplace_front((Edge){v,w});
e[v].emplace_front((Edge){u,w});
}
int n,m,s,t,k,a,b;
class FotileTree {
#define mid ((b+e)>>1)
private:
struct Node {
int sum;
int64 val;
int left,right;
std::pair<int,int64> operator + (const Node &rhs) const {
return std::make_pair(sum+rhs.sum,val+rhs.val);
}
friend std::pair<int,int64> operator - (const std::pair<int,int64> &lhs,const Node &rhs) {
return std::make_pair(lhs.first-rhs.sum,lhs.second-rhs.val);
}
Node operator * (const int &rhs) const {
return {sum*rhs,val*rhs};
}
};
Node node[N*logW];
int sz,new_node(const int &p) {
node[++sz]=node[p];
return sz;
}
public:
int root[N];
void reset() {
sz=0;
}
void insert(int &p,const int &b,const int &e,const int &x) {
p=new_node(p);
node[p].sum++;
node[p].val+=x;
if(b==e) return;
if(x<=mid) insert(node[p].left,b,mid,x);
if(x>mid) insert(node[p].right,mid+1,e,x);
}
std::pair<int,int64> query(const int &p,const int &q,const int &r,const int &b,const int &e,const int64 &x) const {
if(node[p]+node[q]-node[r]*2==std::make_pair(0,0ll)) return std::make_pair(0,0);
if(x>=e) return node[p]+node[q]-node[r]*2;
if(x<=mid) {
return query(node[p].left,node[q].left,node[r].left,b,mid,x);
} else {
const auto p1=query(node[p].left,node[q].left,node[r].left,b,mid,x);
const auto p2=query(node[p].right,node[q].right,node[r].right,mid+1,e,x);
return std::make_pair(p1.first+p2.first,p1.second+p2.second);
}
}
#undef mid
};
FotileTree tr;
void reset() {
for(register int i=1;i<=n;i++) e[i].clear();
tr.reset();
}
inline int lg2(const float &x) {
return ((unsigned&)x>>23&255)-127;
}
int anc[N][logN],min[N][logN]={{INT_MAX}},dep[N];
void dfs(const int &x,const int &par) {
anc[x][0]=par;
dep[x]=dep[par]+1;
for(register int i=1;i<=lg2(dep[x]);i++) {
anc[x][i]=anc[anc[x][i-1]][i-1];
min[x][i]=std::min(min[x][i-1],min[anc[x][i-1]][i-1]);
}
for(auto &i:e[x]) {
const int &y=i.first,&w=i.second;
if(y==par) continue;
tr.insert(tr.root[y]=tr.root[x],0,W,min[y][0]=w);
dfs(y,x);
}
}
int get_min(int x,int y) {
if(dep[x]<dep[y]) std::swap(x,y);
int ret=INT_MAX;
for(register int i=lg2(dep[x]-dep[y]);i>=0;i--) {
if(dep[anc[x][i]]>=dep[y]) {
ret=std::min(ret,min[x][i]);
x=anc[x][i];
}
}
if(x==y) return ret;
for(register int i=lg2(dep[x]);i>=0;i--) {
if(anc[x][i]!=anc[y][i]) {
ret=std::min(ret,min[x][i]);
ret=std::min(ret,min[y][i]);
x=anc[x][i];
y=anc[y][i];
}
}
ret=std::min(ret,min[x][0]);
ret=std::min(ret,min[y][0]);
return ret;
}
inline int get_lca(int x,int y) {
if(dep[x]<dep[y]) std::swap(x,y);
for(register int i=lg2(dep[x]-dep[y]);i>=0;i--) {
if(dep[anc[x][i]]>=dep[y]) {
x=anc[x][i];
}
}
if(x==y) return x;
for(register int i=lg2(dep[x]);i>=0;i--) {
if(anc[x][i]!=anc[y][i]) {
x=anc[x][i];
y=anc[y][i];
}
}
return anc[x][0];
}
inline bool check(const int64 &mid) {
const auto tmp=tr.query(tr.root[s],tr.root[t],tr.root[get_lca(s,t)],0,W,mid);
return tmp.first*mid-tmp.second<=k/b;
}
int main() {
const int T=getint();
for(register int i=1;i<=T;i++) {
printf("Case #%d:\n",i);
n=getint(),m=getint();
for(register int i=1;i<n;i++) {
const int u=getint(),v=getint(),w=getint();
add_edge(u,v,w);
}
dfs(1,0);
for(register int i=0;i<m;i++) {
s=getint(),t=getint(),k=getint(),a=getint(),b=getint();
const int min=get_min(s,t);
if(a<=b) {
printf("%lld\n",min+(int64)k/a);
continue;
}
int64 l=min+(int64)k/a+1,r=min+(int64)k/b;
while(l<=r) {
const int64 mid=(l+r)>>1;
if(check(mid)) {
l=mid+1;
} else {
r=mid-1;
}
}
printf("%lld\n",k>=a?std::max(min+1+(int64)(k-a)/b,l-1):l-1);
}
reset();
}
return 0;
}
[HDU4729]An Easy Problem for Elfness的更多相关文章
- 数据结构(主席树):HDU 4729 An Easy Problem for Elfness
An Easy Problem for Elfness Time Limit: 5000/2500 MS (Java/Others) Memory Limit: 65535/65535 K (J ...
- HDU 4729 An Easy Problem for Elfness(主席树)(2013 ACM/ICPC Asia Regional Chengdu Online)
Problem Description Pfctgeorge is totally a tall rich and handsome guy. He plans to build a huge wat ...
- HDU 4729 An Easy Problem for Elfness(树链剖分边权+二分)
题意 链接:https://cn.vjudge.net/problem/HDU-4729 给你n个点,然你求两个点s和t之间的最大流.而且你有一定的钱k,可以进行两种操作 1.在任意连个点之间建立一个 ...
- 【HDOJ】4729 An Easy Problem for Elfness
其实是求树上的路径间的数据第K大的题目.果断主席树 + LCA.初始流量是这条路径上的最小值.若a<=b,显然直接为s->t建立pipe可以使流量最优:否则,对[0, 10**4]二分得到 ...
- HDU 4729 An Easy Problem for Elfness (主席树,树上第K大)
转载请注明出处,谢谢http://blog.csdn.net/ACM_cxlove?viewmode=contents by---cxlove 题意:给出一个带边权的图.对于每一个询问(S , ...
- HDU 4729 An Easy Problem for Elfness 主席树
题意: 给出一棵树,每条边有一个容量. 有若干次询问:\(S \, T \, K \, A \, B\),求路径\(S \to T\)的最大流量. 有两种方法可以增大流量: 花费\(A\)可以新修一条 ...
- UVA-11991 Easy Problem from Rujia Liu?
Problem E Easy Problem from Rujia Liu? Though Rujia Liu usually sets hard problems for contests (for ...
- An easy problem
An easy problem Time Limit:3000MS Memory Limit:32768KB 64bit IO Format:%I64d & %I64u Sub ...
- UVa 11991:Easy Problem from Rujia Liu?(STL练习,map+vector)
Easy Problem from Rujia Liu? Though Rujia Liu usually sets hard problems for contests (for example, ...
随机推荐
- python碎片记录(二)
1.字典中嵌套字典使用 dict={'a':{1:2,2:3}} print(dict) print(dict['a'][2]) 输出如下: {'a': {1: 2, 2: 3}} 3 2.元组与l ...
- 初识费用流 模板(spfa+slf优化) 餐巾计划问题
今天学习了最小费用最大流,是网络流算法之一.可以对于一个每条边有一个容量和一个费用(即每单位流的消耗)的图指定一个源点和汇点,求在从源点到汇点的流量最大的前提下的最小费用. 这里讲一种最基础也是最好掌 ...
- 【bzoj1649】Cow Roller Coaster
傻逼dp题. dp[i][j]表示用了i长度已花费成本j所能得到的价值. 然后枚举一下铁轨随便做了. 不行就sort一下. #include<bits/stdc++.h> #define ...
- 根据日期查询年龄js
function ages(str) { var r = str.match(/^(\d{1,4})(-|\/)(\d{1,2})\2(\d{1,2})$/); if(r==null)return f ...
- 《Java编程思想》阅读笔记一
Java编程思想 这是一个通过对<Java编程思想>(Think in java)第四版进行阅读同时对java内容查漏补缺的系列.一些基础的知识不会被罗列出来,这里只会列出一些程序员经常会 ...
- find命令的基本用法
linux 中find 常用示例解析 find [-H] [-L] [-P] [-D debugopts] [-Olevel] [path…] [expression] 其实[-H] [-L] [- ...
- 遇见Python.h: No such file or directory的解决方法
出现No such file or directory的错误,有两种情况,一种是没有Python.h这个文件,一种是Python的版本不对, 可以进入/usr/include/文件夹下的Pythonx ...
- 微信小程序~触摸相关事件(拖拽操作、手势识别、多点触控)
touchstart 手指触摸动作开始 touchmove 手指触摸后移动 touchcancel 手指触摸动作被打断,如来电提醒,弹窗 touchend 手指触摸动作结束 ...
- AC日记——[Sdoi2010]粟粟的书架 bzoj 1926
1926 思路: 主席树+二分水题: 代码: #include <bits/stdc++.h> using namespace std; #define maxn 500005 #defi ...
- 网站页面SEO的三个标签怎么写有利【转载】
转载自:代明博客 在SEO界,自从夫唯老师提出“四处一词”的概念以来,不管是搜索引擎还是SEOer,都格外重视页面的三个标签.三个标签书写是否成功,在很大程度上决定了网页是否能有好的排名.今天代明博客 ...