zoukankan      html  css  js  c++  java
  • [HDU4729]An Easy Problem for Elfness

    [HDU4729]An Easy Problem for Elfness

    题目大意:

    给你一棵(n(nle10^5))个点的树,树上每条边都有容量。

    (m(mle10^5))次询问,每次询问你有(k)的预算,可以花(a)的代价在任意两点间建一条流容量为(1)的边(包括重边),或者花费(b)的代价将某条边的容量加(1),问在不超过预算的情况下,从(s)(t)的最大流量。

    思路:

    首先,考虑没有(k,a,b)的情况,答案就是(s,t)路径上的权值最小值(min)

    对于(ale b)的情况,由于我们每在(s)(t)之间新建一条边都能增加(1)的容量,则我们把所有的预算都用来新建边肯定是最优策略。答案是(min+lfloorfrac ka floor)

    对于(a>b)的情况,我们有以下两种可能最优的策略:

    1. 花费(a)的代价新建一条边,然后用剩下的所有预算扩充这条新边的容量。
    2. 不断将路径上最小边扩充(1)的容量。

    对于第一种策略,我们不难得到答案就是(min+1+lfloorfrac{k-a}b floor)

    对于第二种策略,我们可以二分答案(mid)。设路径上边容量(<mid)的边数有(c)个,权值和为(w)。则(c imes mid-w)就是需要扩充的容量之和。若(c imes mid-wlelfloorfrac kb floor),则(ans>=mid),反之(ans<mid)

    上文提及的边数与权值和可以用树上主席树方便地求得。

    时间复杂度(mathcal O(nlog^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:
    ",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
    ",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
    ",k>=a?std::max(min+1+(int64)(k-a)/b,l-1):l-1);
    		}
    		reset();
    	}
    	return 0;
    }
    
  • 相关阅读:
    TTL与RS-485电平转换芯片MAX485/MAX3485
    RS485芯片介绍及典型应用电路
    脉冲电能表的组成及脉冲装置工作原理
    django-redis的安装及使用
    Python折线图——机器人UPtime Trend Chart
    ASP.Net DropDownList控件的使用方法
    C# ASP.Net数据库连接(Oracle)
    django根据已有数据库表生成model类
    Python Outlook发送邮件
    oracle将excel数据导入数据库
  • 原文地址:https://www.cnblogs.com/skylee03/p/9300983.html
Copyright © 2011-2022 走看看