zoukankan      html  css  js  c++  java
  • BZOJ 3218 UOJ #77 A+B Problem (主席树、最小割)

    大名鼎鼎的A+B Problem, 主席树优化最小割……

    调题死活调不对,一怒之下改了一种写法交上去A了,但是改写法之后第4,5个点常数变大很多,于是喜提UOJ全站倒数第三

    目前还不知道原来的写法为什么是错的,暂时先写一下A掉的那种写法的题解。

    题目链接:

    (BZOJ) https://www.lydsy.com/JudgeOnline/problem.php?id=3218

    (UOJ) http://uoj.ac/problem/77

    题解:

    首先不难想到这样的最小割建图: (醒醒吧这种题就别老忘二分图上想了) 下文用(Edge(u,v,w))表示从(u)(v)连一条边权为(w)的单向边, (S,T)分别是源点和汇点

    对每一个方格建一个点(V_i),然后(Edge(S,V_i,b_i), Edge(V_i,T,w_i)), 这样一来这个点属于(T)集((S)的边被割掉了)就表示这个点染成白色(舍弃(b_i)代价), 否则染成黑色。

    此外对于每个方格再建新点(E_i), 然后(Edge(V_i,E_i,p_i)), 再对于满足(1le jle i, a_jin[l_i,r_i])(j), (Edge(E_i,V_j,+inf)), 表示那个奇怪的方格的限制

    至此网络流建模结束。这个还是比较好想的,然而边数(O(n^2)), (TLE+MLE)不谢。

    然后我们考虑如果只有(l_ile a_ile r_i)这个限制,我们可以对(a_i)排序离散化之后转化成了(E_i)这个点要向一个区间内的(V_j)连边,这样的话我们可以建出一棵线段树,线段树每个节点向它的两个儿子连边,然后往区间连边相当于往这个区间拆成的(O(log n))个线段树节点连边,边数(O(log n)).

    然而这题……还要(1le jle i)?

    这样我们就要把线段树改成主席树(vfk大毒瘤!)

    后面的都是套路: 以(i)为历史版本(a_i)为下标建主席树,然后主席树的每个节点往儿子连边,其余的连边方式自行思考(很无脑),详见代码。

    有一个地方需要注意: 有种可能是我往主席树里插入一个节点的时候,主席树这个节点上已经有值了。(也就是存在两个(a_i)相等的情况)

    这怎么办呢?目前我还没有找到一个我认为合理的解决方法,最后直接简单粗暴地离散化的时候不去重,强行把相等变成不等的办法,导致UOJ上第4,5个点常数爆炸跑得和第9,10个点一样慢,全站倒数第三,不过还是过了。

    然后是目前这题的一些还未解决的问题,我想到了若干种弥补相等问题的做法,结果全都是50分或者80分,目前相对来说最靠谱的一种(答案和正确答案相差最小)是对于每一个重叠的主席树节点(T_i)新建一个点(T_i'), (Edge(T_{fa_i},T_i',+inf), Edge(T_i',T_i,+inf), Edge(T_i',T_j',+inf)) ((fa_i)表示主席树的父亲节点, (j,j')是上一个历史版本的对应节点)。然而还是(80)分QAQ……所以哪位大佬能跟我说一下这个到底怎么解决啊,谢谢QwQ

    代码实现

    离散化时不去重的版本,全站倒数第三

    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    #include<cassert>
    #define llong long long
    using namespace std;
    
    const int N = 8e4;
    const int M = 1e6;
    const llong INF = 100000000000ll;
    namespace NetFlow
    {
    	struct Edge
    	{
    		int v,nxt,rev; llong w;
    	} e[(M<<1)+3];
    	int dep[N+3];
    	int te[N+3];
    	int fe[N+3];
    	int que[N+3];
    	int n,en,s,t;
    	void addedge(int u,int v,llong w)
    	{
    //		printf("addedge %d %d %lld
    ",u,v,w);
    		en++; e[en].v = v; e[en].w = w;
    		e[en].nxt = fe[u]; fe[u] = en; e[en].rev = en+1;
    		en++; e[en].v = u; e[en].w = 0;
    		e[en].nxt = fe[v]; fe[v] = en; e[en].rev = en-1;
    	}
    	bool bfs()
    	{
    		for(int i=1; i<=n; i++) dep[i] = 0;
    		int head = 1,tail = 1; que[1] = s; dep[s] = 1;
    		while(head<=tail)
    		{
    			int u = que[head]; head++;
    			for(int i=fe[u]; i; i=e[i].nxt)
    			{
    				if(dep[e[i].v]==0 && e[i].w)
    				{
    					dep[e[i].v] = dep[u]+1;
    					tail++; que[tail] = e[i].v;
    				}
    			}
    		}
    		return dep[t]!=0;
    	}
    	llong dfs(int u,llong cur)
    	{
    		if(u==t) return cur;
    		llong rst = cur;
    		for(int i=te[u]; i; i=e[i].nxt)
    		{
    			if(dep[e[i].v]==dep[u]+1 && rst>0 && e[i].w>0)
    			{
    				llong flow = dfs(e[i].v,min(e[i].w,rst));
    				if(flow>0)
    				{
    					e[i].w-=flow; rst-=flow; e[e[i].rev].w+=flow;
    					if(e[i].w>0) {te[u] = i;}
    					if(rst==0) return cur;
    				}
    			}
    		}
    		if(cur==rst) dep[u] = 0;
    		return cur-rst;
    	}
    	llong dinic()
    	{
    //		printf("Dinic n=%d
    ",n);
    		llong ret = 0ll;
    		while(bfs())
    		{
    			for(int i=1; i<=n; i++) te[i] = fe[i];
    			ret += dfs(s,INF);
    		}
    		return ret;
    	}
    }
    using NetFlow::addedge;
    using NetFlow::dinic;
    
    struct Element
    {
    	llong b,w,p; int a,l,r; int id;
    	bool operator <(const Element &arg) const
    	{
    		return a<arg.a;
    	}
    } a[N+3],b[N+3];
    struct SgTNode
    {
    	int ls,rs;
    } sgt[N+3];
    vector<int> disc;
    int rtn[N+3];
    int n,siz;
    
    int getdisc(int x)
    {
    	return lower_bound(disc.begin(),disc.end(),x)-disc.begin()+1;
    }
    
    void addval(int &pos,int le,int ri,int lrb,int id,llong w1,llong w2,llong w3)
    {
    	siz++; sgt[siz] = sgt[pos];
    	pos = siz;
    	if(le==ri) {addedge(1,pos,w1); addedge(pos,id,w3); addedge(pos,2,w2); return;}
    	int mid = (le+ri)>>1;
    	if(lrb<=mid) {addval(sgt[pos].ls,le,mid,lrb,id,w1,w2,w3);}
    	else {addval(sgt[pos].rs,mid+1,ri,lrb,id,w1,w2,w3);}
    	if(sgt[pos].ls) {addedge(pos,sgt[pos].ls,INF);} //Judge 0
    	if(sgt[pos].rs) {addedge(pos,sgt[pos].rs,INF);}
    }
    
    void AddEdge(int pos,int le,int ri,int lb,int rb,int id)
    {
    	if(pos==0) return;
    	if(lb<=le && rb>=ri) {addedge(id,pos,INF); return;}
    	int mid = (le+ri)>>1;
    	if(lb<=mid) {AddEdge(sgt[pos].ls,le,mid,lb,rb,id);}
    	if(rb>mid) {AddEdge(sgt[pos].rs,mid+1,ri,lb,rb,id);}
    }
    
    int main()
    {
    	scanf("%d",&n);
    	for(int i=1; i<=n; i++)
    	{
    		scanf("%d%lld%lld%d%d%lld",&a[i].a,&a[i].b,&a[i].w,&a[i].l,&a[i].r,&a[i].p); a[i].id = i;
    		disc.push_back(a[i].a);
    	}
    	sort(disc.begin(),disc.end());
    	sort(a+1,a+n+1);
    	for(int i=1; i<=n; i++)
    	{
    		a[i].l = getdisc(a[i].l);
    		a[i].r = getdisc(a[i].r+1)-1;
    		if(a[i].l<1) a[i].l = 1;
    		if(a[i].r>disc.size()) a[i].r = disc.size();
    		a[i].a = i;
    		b[a[i].id] = a[i];
    	}
    	for(int i=1; i<=n; i++) a[i] = b[i];
    //	for(int i=1; i<=n; i++) printf("%d %lld %lld %d %d %lld
    ",a[i].a,a[i].b,a[i].w,a[i].l,a[i].r,a[i].p);
    	siz = n+2;
    	rtn[0] = 0;
    	for(int i=1; i<=n; i++)
    	{
    //		printf("i%d:
    ",i);
    		rtn[i] = rtn[i-1];
    		addval(rtn[i],1,disc.size(),a[i].a,i+2,a[i].b,a[i].w,a[i].p);
    		AddEdge(rtn[i-1],1,disc.size(),a[i].l,a[i].r,i+2);
    //		printf("siz=%d
    ",siz);
    //		for(int j=1; j<=i; j++) printf("rtn[%d]=%d
    ",j,rtn[j]);
    //		for(int j=n+3; j<=siz; j++) printf("i%d ls%d rs%d
    ",j,sgt[j].ls,sgt[j].rs);
    //		puts("");
    	}
    	NetFlow::n = siz; NetFlow::s = 1; NetFlow::t = 2;
    	llong ans = 0ll;
    	for(int i=1; i<=n; i++) ans += a[i].b+a[i].w;
    	ans = ans-dinic();
    	printf("%lld
    ",ans);
    	return 0;
    }
    /*
    3
    3 1 6 2 2 3
    3 2 9 1 5 8
    4 3 8 2 4 7
    */
    

    附: 80分代码

    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    #include<cassert>
    #define llong long long
    using namespace std;
    
    const int N = 8e4;
    const int M = 1e6;
    const llong INF = 100000000000ll;
    namespace NetFlow
    {
    	struct Edge
    	{
    		int v,nxt,rev; llong w;
    	} e[(M<<1)+3];
    	int dep[N+3];
    	int te[N+3];
    	int fe[N+3];
    	int que[N+3];
    	int n,en,s,t;
    	void addedge(int u,int v,llong w)
    	{
    //		printf("addedge %d %d %lld
    ",u,v,w);
    		en++; e[en].v = v; e[en].w = w;
    		e[en].nxt = fe[u]; fe[u] = en; e[en].rev = en+1;
    		en++; e[en].v = u; e[en].w = 0;
    		e[en].nxt = fe[v]; fe[v] = en; e[en].rev = en-1;
    	}
    	bool bfs()
    	{
    		for(int i=1; i<=n; i++) dep[i] = 0;
    		int head = 1,tail = 1; que[1] = s; dep[s] = 1;
    		while(head<=tail)
    		{
    			int u = que[head]; head++;
    			for(int i=fe[u]; i; i=e[i].nxt)
    			{
    				if(dep[e[i].v]==0 && e[i].w)
    				{
    					dep[e[i].v] = dep[u]+1;
    					tail++; que[tail] = e[i].v;
    				}
    			}
    		}
    		return dep[t]!=0;
    	}
    	llong dfs(int u,llong cur)
    	{
    		if(u==t) return cur;
    		llong rst = cur;
    		for(int i=te[u]; i; i=e[i].nxt)
    		{
    			if(dep[e[i].v]==dep[u]+1 && rst>0 && e[i].w>0)
    			{
    				llong flow = dfs(e[i].v,min(e[i].w,rst));
    				if(flow>0)
    				{
    					e[i].w-=flow; rst-=flow; e[e[i].rev].w+=flow;
    					if(e[i].w>0) {te[u] = i;}
    					if(rst==0) return cur;
    				}
    			}
    		}
    		if(cur==rst) dep[u] = 0;
    		return cur-rst;
    	}
    	llong dinic()
    	{
    //		printf("Dinic n=%d
    ",n);
    		llong ret = 0ll;
    		while(bfs())
    		{
    			for(int i=1; i<=n; i++) te[i] = fe[i];
    			ret += dfs(s,INF);
    		}
    		return ret;
    	}
    }
    using NetFlow::addedge;
    using NetFlow::dinic;
    
    struct Element
    {
    	llong b,w,p; int a,l,r;
    } a[N+3];
    struct SgTNode
    {
    	int ls,rs,prv;
    } sgt[N+3];
    vector<int> disc;
    int rtn[N+3];
    int n,siz;
    
    int getdisc(int x)
    {
    	return lower_bound(disc.begin(),disc.end(),x)-disc.begin()+1;
    }
    
    void addval(int &pos,int le,int ri,int lrb,int id,llong w1,llong w2,llong w3,int prv)
    {
    	siz++; sgt[siz] = sgt[pos];
    	if(le==ri && pos!=0) {siz++; addedge(prv,siz,INF); addedge(siz,siz-1,INF); addedge(siz,sgt[pos].prv,INF); pos = siz-1; sgt[pos].prv = siz;}
    	else pos = siz,sgt[pos].prv = siz;
    	if(le==ri) {addedge(1,pos,w1); addedge(pos,id,w3); addedge(pos,2,w2); return;}
    	int mid = (le+ri)>>1;
    	if(lrb<=mid) {addval(sgt[pos].ls,le,mid,lrb,id,w1,w2,w3,pos);}
    	else {addval(sgt[pos].rs,mid+1,ri,lrb,id,w1,w2,w3,pos);}
    	if(sgt[pos].ls) {addedge(pos,sgt[pos].ls,INF);} //Judge 0
    	if(sgt[pos].rs) {addedge(pos,sgt[pos].rs,INF);}
    }
    
    void AddEdge(int pos,int le,int ri,int lb,int rb,int id)
    {
    	if(pos==0) return;
    	if(lb<=le && rb>=ri) {addedge(id,pos,INF); return;}
    	int mid = (le+ri)>>1;
    	if(lb<=mid) {AddEdge(sgt[pos].ls,le,mid,lb,rb,id);}
    	if(rb>mid) {AddEdge(sgt[pos].rs,mid+1,ri,lb,rb,id);}
    }
    
    int main()
    {
    	scanf("%d",&n);
    	for(int i=1; i<=n; i++)
    	{
    		scanf("%d%lld%lld%d%d%lld",&a[i].a,&a[i].b,&a[i].w,&a[i].l,&a[i].r,&a[i].p);
    		disc.push_back(a[i].a);
    	}
    	sort(disc.begin(),disc.end());
    	disc.erase(unique(disc.begin(),disc.end()),disc.end());
    	for(int i=1; i<=n; i++)
    	{
    		a[i].a = getdisc(a[i].a);
    		a[i].l = getdisc(a[i].l);
    		a[i].r = getdisc(a[i].r+1)-1;
    		if(a[i].l<1) a[i].l = 1;
    		if(a[i].r>disc.size()) a[i].r = disc.size();
    	}
    //	for(int i=1; i<=n; i++) printf("%d %lld %lld %d %d %lld
    ",a[i].a,a[i].b,a[i].w,a[i].l,a[i].r,a[i].p);
    	siz = n+2;
    	rtn[0] = 0;
    	for(int i=1; i<=n; i++)
    	{
    //		printf("i%d:
    ",i);
    		rtn[i] = rtn[i-1];
    		addval(rtn[i],1,disc.size(),a[i].a,i+2,a[i].b,a[i].w,a[i].p,0);
    		AddEdge(rtn[i-1],1,disc.size(),a[i].l,a[i].r,i+2);
    //		printf("siz=%d
    ",siz);
    //		for(int j=1; j<=i; j++) printf("rtn[%d]=%d
    ",j,rtn[j]);
    //		for(int j=1; j<=siz; j++) printf("i%d ls%d rs%d
    ",j,sgt[j].ls,sgt[j].rs);
    //		puts("");
    	}
    	NetFlow::n = siz; NetFlow::s = 1; NetFlow::t = 2;
    	llong ans = 0ll;
    	for(int i=1; i<=n; i++) ans += a[i].b+a[i].w;
    	ans = ans-dinic();
    	printf("%lld
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    小程序登录java后端实现
    Lambda 表达式应用
    java8 实现List对象去重
    实现二:Map<Long, List<Long>> 存放的value 可能含有重复元素,将value 中含有重复元素的Map 重新组合
    实现一:多个List 可能含有重复元素,含有重复元素的集合重新组合
    SpringBoot整合rabbitMq实现消息延时发送
    spring 中aop 切面实战
    MySQL 使用AVG聚合函数时,保留两位小数的方法
    使用Java实现图片等其他文件的本地复制
    Java中初始化集合的方法
  • 原文地址:https://www.cnblogs.com/suncongbo/p/10325227.html
Copyright © 2011-2022 走看看