zoukankan      html  css  js  c++  java
  • 题解 P2619 【[国家集训队2]Tree I】

    题目链接

    推荐FlashHu的博客,用导数来理解(wqs)二分真的太妙啦,也解释为啥必须是凸函数才能用(wqs)二分

    还有Creeper_LKF的数形结合的博客

    Solution Tree I

    题目大意:每条有黑白颜色,求恰好选择(need)条白色边条件下的最小生成树

    (wqs)二分


    分析:设(g(x))为恰好选(x)条白边的最小生成树权值和,那么经过打表我们可以猜想证明出(g)是一个下凸函数(其实可以(dp)的……)

    然后我们就可以用(wqs)二分了

    这玩意儿通常用来解决有某种限制,每个物品有个权值,钦定必须选(x)个时候的最大/小权值和

    要求函数(g)必须是凸函数,这样我们才可以对导函数进行二分

    以上凸函数为例,我们要求的是(g)在给定的(m)处的取值,显然我们没法直接算出来(废话,不然干嘛不直接算,雾)

    但是我们可以通过贪心 / (dp)等等来求出不考虑限制的时候的最大函数值,顺带求出自变量的值。然后我们看这个函数(g)的导函数(g'),当(g)取到最大值的时候(g')(x)

    如果我们把(g(x))加上(kx)的话,不就等价于把导函数向上平移(k)个单位了吗

    我们二分(k),使得导函数交(x)轴于我们期望的(m),然后这个时候我们就可以求出(g(m))

    完了?naive

    我们加上了(kx),也就是对(g(m))加上了(km),记得减掉

    此题同理,我们二分一个(k),对所有白边的权值加上(k),跑(Kruskal)即可

    黑白边同权选白边,然后没必要每次都做快排,可以黑白边分开然后每次跑归并排序,这样可以省下一个(log)的复杂度

    #include <cstdio>
    #include <cctype>
    #include <algorithm>
    using namespace std;
    const int maxn = 1e5 + 100;
    inline int read(){
    	int x = 0;char c = getchar();
    	while(!isdigit(c))c = getchar();
    	while(isdigit(c))x = x * 10 + c - '0',c = getchar();
    	return x;
    }
    struct Edge{
    	int from,to,dist,col;
    }Edges[maxn],black[maxn],white[maxn];
    int f[maxn],n,m,need,sz,black_siz,white_siz;
    inline void init(){
    	for(int i = 1;i <= n;i++)f[i] = i;
    	sz = n;
    }
    inline int find(int x){
    	return (x == f[x]) ? x : f[x] = find(f[x]);
    }
    inline void merge(int a,int b){
    	int x = find(a),y = find(b);
    	if(x != y){
    		sz--;
    		f[x] = y;
    	}
    }
    inline int kruskal(int delta){
    	int res = 0,posa = 1,posb = 1,tot = 0;
    	while(posa <= white_siz && posb <= black_siz)
    		if(white[posa].dist + delta <= black[posb].dist)Edges[++tot] = white[posa++],Edges[tot].dist += delta;
    		else Edges[++tot] = black[posb++];
    	while(posa <= white_siz)Edges[++tot] = white[posa++],Edges[tot].dist += delta;;
    	while(posb <= black_siz)Edges[++tot] = black[posb++];
    	init();
    	for(int i = 1;i <= m && sz != 1;i++){
    		const Edge &e = Edges[i];
    		if(find(e.from) != find(e.to))res += !e.col;
    		merge(e.from,e.to);
    	}
    	return res;
    }
    int main(){
    	n = read(),m = read(),need = read();
    	for(int u,v,w,c,i = 1;i <= m;i++){
    		u = read() + 1,v = read() + 1,w = read(),c = read();
    		if(c == 0)white[++white_siz] = Edge{u,v,w,c};
    		else black[++black_siz] = Edge{u,v,w,c};
    	}
    	sort(white + 1,white + 1 + white_siz,[](const Edge &a,const Edge &b){return a.dist < b.dist;});
    	sort(black + 1,black + 1 + black_siz,[](const Edge &a,const Edge &b){return a.dist < b.dist;});
    	int l = -111,r = 111,ans = 233;
    	while(l <= r){
    		int mid = (l + r) >> 1,tmp = kruskal(mid);
    		if(tmp < need)r = mid - 1;
    		else ans = mid,l = mid + 1;
    	}
    	if(ans == 233)abort();
    	int posa = 1,posb = 1,tot = 0;
    	while(posa <= white_siz && posb <= black_siz)
    		if(white[posa].dist + ans <= black[posb].dist)Edges[++tot] = white[posa++],Edges[tot].dist += ans;
    		else Edges[++tot] = black[posb++];
    	while(posa <= white_siz)Edges[++tot] = white[posa++],Edges[tot].dist += ans;
    	while(posb <= black_siz)Edges[++tot] = black[posb++];
    	init();
    	ans *= -need;
    	for(int i = 1;i <= m && sz != 1;i++){
    		const Edge &e = Edges[i];
    		if(find(e.from) != find(e.to))ans += e.dist;
    		merge(e.from,e.to);
    	}
    	printf("%d
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    PAIRING WORKFLOW MANAGER 1.0 WITH SHAREPOINT 2013
    Education resources from Microsoft
    upgrade to sql server 2012
    ULSViewer sharepoint 2013 log viewer
    Top 10 Most Valuable Microsoft SharePoint 2010 Books
    讨论 Setsockopt选项
    使用 Alchemy 技术编译 C 语言程序为 Flex 可调用的 SWC
    Nagle's algorithm
    Nagle算法 TCP_NODELAY和TCP_CORK
    Design issues Sending small data segments over TCP with Winsock
  • 原文地址:https://www.cnblogs.com/colazcy/p/11771534.html
Copyright © 2011-2022 走看看