zoukankan      html  css  js  c++  java
  • BZOJ2138 stone

    stone

    话说Nan在海边等人,预计还要等上M分钟。为了打发时间,他玩起了石子。Nan搬来了N堆石子,编号为1到N,每堆包含Ai颗石子。每1分钟,Nan会在编号在[Li,Ri]之间的石堆中挑出任意Ki颗扔向大海(好疼的玩法),如果[Li,Ri]剩下石子不够Ki颗,则取尽量地多。

    为了保留扔石子的新鲜感,Nan保证任意两个区间[Li,Ri]和[Lj,Rj],不会存在Li<=Lj&Rj<=Ri的情况,即任意两段区间不存在包含关系。

    可是,如果选择不当,可能无法扔出最多的石子,这时NN就会不高兴了。所以他希望制定一个计划,他告诉你他m分钟打算扔的区间[Li,Ri]以及Ki。现在他想你告诉
    他,在满足前i-1分钟都取到你回答的颗数的情况下,第i分钟最多能取多少个石子。

    N<=40000

    题解

    https://www.cnblogs.com/cjyyb/p/9301820.html

    考虑一个暴力。每堆石子和每个询问,显然是匹配的操作。

    所以可以把石子拆成ai个,询问点拆成Ki个,这样就是每次进行一次二分图的匹配。当然可以用网络流+线段树优化连边来做,但是这样复杂度太高。

    还是回到二分图的匹配问题,我们现在要验证的就是是否存在对于当前询问点的完美匹配。

    关于完美匹配,有Hall定理,如果存在完美匹配,假设左侧的点有|X|个,那么这些点连向右边的点的点集的并Y,满足|X|≤|Y|

    因为询问点拆开后,每个点的连向右边的点集都是一样的,所以相当于就是Ki≤|Y|

    只提取出所有有用的石子,按顺序编号。设si表示前i堆石子的个数和。

    如果存在完美匹配,那么在任意时刻,所有存在于区间[L,R]之内的询问的石子个数的总和T[L,R]一定小于区间[L,R]之内的石子的总和。

    也就是sR−sL−1≥T[L,R],发现题目中的性质,任何询问不存在包含关系。

    那么我们假设TLi表示左端点在[1,i]中的询问的总和,TRi表示右端点在[1,i]中的询问的总和。

    那么因为T[L,R]=TRR−TLL−1,所以我们也可以很容易的表示出T来。

    所以,现在的不等式表达为s[R]−s[L−1]≥TR[R]−TL[L−1]

    所以s[R]−TR[R]≥s[L−1]−TL[L−1]

    设f[i]=s[i]−TR[i],g[i]=s[i]−TL[i],所以是f[R]≥g[L−1]

    我们发现,如果从[L,R]区间中拿走若干石头,在不等式中变化的只有TR[R]

    也就是只有f[i]会减小。所以我们能够拿走的数量为min(K[i],f[R]−g[L−1])

    对于当前询问区间[L,R],会对于所有的x∈[1,L],y∈[R,n],[x,y]产生影响

    也就是任何包含当前区间的区间也需要满足Hall定理,在本题中也就是f[y]≥g[x]

    那么当前步的答案就是所有的min(K[i],f[y]−g[x]),那么取后缀f最小值,前缀g最大值即可。

    每次拿线段树区间更新一下即可。

    CO int N=3e5+10;
    int sum[N];
    
    namespace mn{
    	int val[4*N],tag[4*N];
    	
    	#define lc (x<<1)
    	#define rc (x<<1|1)
    	#define mid ((l+r)>>1)
    	IN void push_up(int x){
    		val[x]=min(val[lc],val[rc]);
    	}
    	IN void push_down(int x){
    		if(tag[x]){
    			val[lc]+=tag[x],tag[lc]+=tag[x];
    			val[rc]+=tag[x],tag[rc]+=tag[x];
    			tag[x]=0;
    		}
    	}
    	void build(int x,int l,int r){
    		if(l==r) {val[x]=sum[l]; return;}
    		build(lc,l,mid),build(rc,mid+1,r);
    		push_up(x);
    	}
    	void modify(int x,int l,int r,int ql,int qr,int v){
    		if(ql<=l and r<=qr) {val[x]+=v,tag[x]+=v; return;}
    		push_down(x);
    		if(ql<=mid) modify(lc,l,mid,ql,qr,v);
    		if(qr>mid) modify(rc,mid+1,r,ql,qr,v);
    		push_up(x);
    	}
    	int query(int x,int l,int r,int ql,int qr){
    		if(ql<=l and r<=qr) return val[x];
    		push_down(x);
    		if(qr<=mid) return query(lc,l,mid,ql,qr);
    		if(ql>mid) return query(rc,mid+1,r,ql,qr);
    		return min(query(lc,l,mid,ql,qr),query(rc,mid+1,r,ql,qr));
    	}
    	#undef lc
    	#undef rc
    	#undef mid
    }
    
    namespace mx{
    	int val[4*N],tag[4*N];
    	
    	#define lc (x<<1)
    	#define rc (x<<1|1)
    	#define mid ((l+r)>>1)
    	IN void push_up(int x){
    		val[x]=max(val[lc],val[rc]);
    	}
    	IN void push_down(int x){
    		if(tag[x]){
    			val[lc]+=tag[x],tag[lc]+=tag[x];
    			val[rc]+=tag[x],tag[rc]+=tag[x];
    			tag[x]=0;
    		}
    	}
    	void build(int x,int l,int r){
    		if(l==r) {val[x]=sum[l]; return;}
    		build(lc,l,mid),build(rc,mid+1,r);
    		push_up(x);
    	}
    	void modify(int x,int l,int r,int ql,int qr,int v){
    		if(ql<=l and r<=qr) {val[x]+=v,tag[x]+=v; return;}
    		push_down(x);
    		if(ql<=mid) modify(lc,l,mid,ql,qr,v);
    		if(qr>mid) modify(rc,mid+1,r,ql,qr,v);
    		push_up(x);
    	}
    	int query(int x,int l,int r,int ql,int qr){
    		if(ql<=l and r<=qr) return val[x];
    		push_down(x);
    		if(qr<=mid) return query(lc,l,mid,ql,qr);
    		if(ql>mid) return query(rc,mid+1,r,ql,qr);
    		return max(query(lc,l,mid,ql,qr),query(rc,mid+1,r,ql,qr));
    	}
    	#undef lc
    	#undef rc
    	#undef mid
    }
    
    int main(){
    	freopen("flandre.in","r",stdin),freopen("flandre.out","w",stdout);
    	int n=read<int>();
    	for(int i=1;i<=n;++i) sum[i]=sum[i-1]+read<int>();
    	mn::build(1,1,n),mx::build(1,0,n);
    	for(int m=read<int>();m--;){
    		int l=read<int>(),r=read<int>(),k=read<int>();
    		k=min(k,mn::query(1,1,n,r,n)-mx::query(1,0,n,0,l-1));
    		mn::modify(1,1,n,r,n,-k),mx::modify(1,0,n,l,n,-k);
    		printf("%d
    ",k);
    	}
    	return 0;
    }
    
  • 相关阅读:
    洛谷P1865 A%B Problem
    树状数组的操作
    树状数组的基础知识
    卡常优化中最为奇怪的操作
    inline的用法
    快速读入的方法
    P1059 明明的随机数及unique去重的用法
    P3376 网络最大流 【模板】
    Gym
    HDU
  • 原文地址:https://www.cnblogs.com/autoint/p/12672402.html
Copyright © 2011-2022 走看看