• 【BZOJ-3218】a+b Problem 最小割 + 可持久化线段树


    3218: a + b Problem

    Time Limit: 20 Sec  Memory Limit: 40 MB
    Submit: 1320  Solved: 498
    [Submit][Status][Discuss]

    Description

    Input

    Output

    Sample Input

    Sample Output

    HINT

    Source

    Solution

    这道题非常吼啊!!

    最小割的解法想一想还是比较容易想到的。

    最大化价值的方法可以看成总和减去最小化损失。

    暴力的解法就是$<S,i,b[i]>$割掉表示选白色,$<i',T,w[i]>$割掉表示选黑色,$<i,i',p[i]>$表示如果$i$和$i'$不同则付出代价,$<i',j,INF>$表示和$j$是不会被割的。

    这样直接求出$mincut$,然后答案就是$sum(b[i]+w[i])-mincut$。

    但是这样的边数是$N^{2}$的,最后会被卡,所以要去优化。

    这类情况的优化比较明显的就是影响的范围是一段区间,所以比较常见的是用线段树的节点去表示对一个区间的影响,来达到优化的目的,即连$<i',seg[l,r],INF>$。

    首先肯定是线段树中的$<fa,son[0/1],INF>$,这里叶子节点直接连所对应的点,即$<leaf_{i},i,INF>$。

    对于$1<=j<i$,可以考虑把普通的线段树换成可持久化线段树即可。

    这里有一个问题就是$a[i]$用同一个叶子节点表示的会出现重复,所以需要新版本的叶子连向老版本的叶子$<new,old,INF>$

    这样边数和点数都是$NlogN$的,就可以通过了。

    搞起来有点蛋疼...思路清晰的话不是很难写。

    Code

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<queue>
    using namespace std;
    inline int read()
    {
    	int x=0,f=1; char ch=getchar();
    	while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();}
    	while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();}
    	return x*f;
    }
    
    #define MAXN 100010
    #define MAXM 750010
    
    int N,a[MAXN],b[MAXN],w[MAXN],l[MAXN],r[MAXN],p[MAXN],ans;
    struct EdgeNode{
    	int next,to,cap;
    }edge[MAXM<<1];
    int head[MAXN],cnt=1;
    inline void AddEdge(int u,int v,int w) {cnt++; edge[cnt].next=head[u]; head[u]=cnt; edge[cnt].to=v; edge[cnt].cap=w;}
    inline void InsertEdge(int u,int v,int w) {/*printf("<%d  %d>
    ",u,v);*/ AddEdge(u,v,w); AddEdge(v,u,0);}
    
    #define INF 0x7fffffff
    int h[MAXN],S,T,cur[MAXN];
    inline bool bfs()
    {
        queue<int>q;
        for (int i=S; i<=T; i++) h[i]=-1;
        h[S]=1; q.push(S);
        while (!q.empty())
            {
                int now=q.front(); q.pop();
                for (int i=head[now]; i; i=edge[i].next)
                    if (h[edge[i].to]==-1 && edge[i].cap)
                        h[edge[i].to]=h[now]+1,q.push(edge[i].to);
            }
        return h[T]!=-1;        
    }
    
    inline int dfs(int loc,int low)
    {
        if (loc==T) return low;
    	int used=0,w;
        for (int i=cur[loc]; i; i=edge[i].next)
            if (edge[i].cap && h[edge[i].to]==h[loc]+1)
                {
                    w=dfs(edge[i].to,min(edge[i].cap,low-used));
                    edge[i].cap-=w; edge[i^1].cap+=w; used+=w;
                    if (used==low) return low;
                    if (edge[i].to) cur[loc]=i;
                }
        if (!used) h[loc]=-1;
        return used;
    }
    
    int Dinic()
    {
        int tmp=0;
        while (bfs())
            {
                for (int i=S; i<=T; i++) cur[i]=head[i];
                tmp+=dfs(S,INF);
            }
        return tmp;
    }
    
    namespace PrTree{
    	int sz,lson[MAXM],rson[MAXM],root[MAXN];
    	inline void Insert(int l,int r,int &x,int y,int pos,int id)
    	{
    		x=++sz;
    		if (l==r) {
    			InsertEdge(2*N+x,id,INF);
    			if (y) InsertEdge(2*N+x,2*N+y,INF);
    			return;	
    		}
    		int mid=(l+r)>>1;
    		lson[x]=lson[y]; rson[x]=rson[y];
    		if (pos<=mid) Insert(l,mid,lson[x],lson[y],pos,id);
    			else Insert(mid+1,r,rson[x],rson[y],pos,id);
    		if (lson[x]) InsertEdge(2*N+x,2*N+lson[x],INF);
    		if (rson[x]) InsertEdge(2*N+x,2*N+rson[x],INF);
    	}
    	
    	inline void Query(int l,int r,int L,int R,int now,int id)
    	{
    		if (!now) return;
    		if (L<=l && R>=r) {
    			InsertEdge(id,2*N+now,INF);
    			return;	
    		}
    		int mid=(l+r)>>1;
    		if (L<=mid) Query(l,mid,L,R,lson[now],id);
    		if (R>mid) Query(mid+1,r,L,R,rson[now],id);
    	}
    
    }using namespace PrTree;
    
    int ls[MAXN],tot;
    int main()
    {
    	N=read();
    	for (int i=1; i<=N; i++) a[i]=read(),b[i]=read(),w[i]=read(),l[i]=read(),r[i]=read(),p[i]=read(),ans+=w[i]+b[i];
    	for (int i=1; i<=N; i++) ls[++tot]=a[i],ls[++tot]=l[i],ls[++tot]=r[i];
    	
    	sort(ls+1,ls+tot+1); tot=unique(ls+1,ls+tot+1)-ls-1;
    	
    	for (int i=1; i<=N; i++) a[i]=lower_bound(ls+1,ls+tot+1,a[i])-ls,l[i]=lower_bound(ls+1,ls+tot+1,l[i])-ls,r[i]=lower_bound(ls+1,ls+tot+1,r[i])-ls;
    	
    	S=0;
    	
    	for (int i=1; i<=N; i++) {
    		PrTree::Insert(1,tot,root[i],root[i-1],a[i],i);
    		PrTree::Query(1,tot,l[i],r[i],root[i-1],i+N);
    	}
    	
    	T=2*N+sz+1;
    	
    	for (int i=1; i<=N; i++) InsertEdge(S,i,b[i]),InsertEdge(i,T,w[i]),InsertEdge(i,i+N,p[i]);
    	
    	printf("%d
    ",ans-Dinic());
    	return 0;
    }
    

      

  • 相关阅读:
    nodejs ---day01
    面向对象
    面向对象
    面向对象
    webpack
    webpack
    webpack
    模块化 (ESM) --- day02
    模块化 --- day01
    轮播图(淡入淡出切换)
  • 原文地址:https://www.cnblogs.com/DaD3zZ-Beyonder/p/6375782.html
Copyright © 2020-2023  润新知