zoukankan      html  css  js  c++  java
  • 【瞎口胡】整体二分

    整体二分是处理多个相似询问的利器。

    例题 [POI2011]MET-Meteors

    题意

    有一个 \(n\) 个节点的环,每个节点都有一个所属国家。共有 \(n\) 个国家,第 \(i\) 个国家的陨石需求量为 \(p_i\)

    现在有 \(k\) 场陨石雨,每次陨石雨会落在 \([l,r]\) 区间内每一个节点上,并使这些节点的陨石数量增加 \(a\)

    询问每个国家至少在第几次陨石雨之后才能达到需求量,或者指出这不可能。

    \(1 \leq n,m ,k \leq 3 \times 10^5,1 \leq p_i,a_i \leq 10^9\)

    题解

    先考虑一个询问是怎么样的。直接二分:如果 \([l,mid]\) 的陨石雨落下来之后达到了需求量,那答案一定 \(\leq mid\),清除 \([l,mid]\) 的陨石雨并递归 \([l,mid]\);否则不清除,递归 \([mid+1,r]\)

    \(n\) 个询问也是一样的。二分,把 \([l,mid]\) 的陨石雨落下来之后可以达到需求量的询问往 \([l,mid]\) 递归,反之往 \([mid+1,r]\) 递归。

    因为最多递归 \(\log\) 次,所以复杂度是 \(O(n \log^2 n)\) 的(\(n,m,k\) 同阶,时间复杂度均以 \(n\) 表示)。

    # include <bits/stdc++.h>
    # define int long long
    const int N=300010,INF=0x3f3f3f3f;
    
    struct Node{
    	int l,r,val,id;
    }a[N<<1];
    int opsum;
    std::vector <int> idx[N];
    
    int n,m,k;
    
    int sum[N],need[N];
    int q1[N],q2[N],q[N],ans[N];
    inline int read(void){
    	int res,f=1;
    	char c;
    	while((c=getchar())<'0'||c>'9')
    		if(c=='-')f=-1;
    	res=c-48;
    	while((c=getchar())>='0'&&c<='9')
    		res=res*10+c-48;
    	return res*f;
    }
    inline int lowbit(int x){
    	return x&(-x);
    }
    inline void add(int x,int v){
    	for(;x<=m;x+=lowbit(x))
    		sum[x]+=v;
    	return;
    }
    inline int query(int x){
    	int ans=0;
    	for(;x;x-=lowbit(x))
    		ans+=sum[x];
    	return ans;
    }
    inline int getsum(int x){
    	int ans=0;
    	for(int i=0;i<(int)idx[x].size();++i){
    		ans+=query(idx[x][i]);
    		if(ans>=need[x])
    			return ans;
    	}
    	return ans;
    }
    void calc(int l,int r,int L,int R){
    	if(L>R)
    		return;	
    		
    	if(l==r){
    		for(int i=L;i<=R;++i)
    			ans[q[i]]=a[l].id;
    		return;
    	}
    	int mid=(l+r)>>1;
    	for(int i=l;i<=mid;++i)
    		add(a[i].l,a[i].val),add(a[i].r+1,-a[i].val);
    
    	int pL=0,pR=0;
    	for(int i=L;i<=R;++i){
    		int now=getsum(q[i]);
    		if(now>=need[q[i]])
    			q1[++pL]=q[i];
    		else
    			q2[++pR]=q[i],need[q[i]]-=now;
    	}
    	for(int i=1;i<=pL;++i)
    		q[L+i-1]=q1[i];
    	for(int i=1;i<=pR;++i)
    		q[L+pL+i-1]=q2[i];
    	for(int i=l;i<=mid;++i)
    		add(a[i].l,-a[i].val),add(a[i].r+1,a[i].val);
    	calc(l,mid,L,L+pL-1),calc(mid+1,r,L+pL,R);
    	return;
    }
    signed main(void){
    	n=read(),m=read();
    	for(int i=1;i<=m;++i)
    		idx[read()].push_back(i);
    	for(int i=1;i<=n;++i)
    		need[i]=read(),q[i]=i;
    	k=read();
    	for(int i=1;i<=k;++i){
    		int l=read(),r=read(),val=read();
    		if(l<=r){
    			a[++opsum].l=l,a[opsum].r=r,a[opsum].val=val,a[opsum].id=i;
    		}else{
    			a[++opsum].l=l,a[opsum].r=m,a[opsum].val=val,a[opsum].id=i;
    			a[++opsum].l=1,a[opsum].r=r,a[opsum].val=val,a[opsum].id=i; // 环形可以拆成两个
    		}
    	}	
    	a[++opsum].l=1,a[opsum].r=m,a[opsum].id=k+1,a[opsum].val=1e9;
    	calc(1,opsum,1,n);
    
    	for(int i=1;i<=n;++i)
    		if(ans[i]==k+1)
    			puts("NIE");
    		else
    			printf("%lld\n",ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    [导入]【翻译】WF从入门到精通(第十三章):打造自定义活动
    [导入]关于网页标准与JAVAScript执行的问题
    html包含html文件的方法
    [导入]C#加密方法汇总
    8、步步为营VS 2008 + .NET 3.5(8) DLINQ(LINQ to SQL)之面向对象的添加、查询、更新和删除
    [导入]【翻译】WF从入门到精通(第十五章):工作流和事务
    [导入]存储过程得到某个表的所有字段信息
    1、步步为营VS 2008 + .NET 3.5(1) VS 2008新特性之Multi Targeting(多定向)、Web Designer and CSS(集成了CSS的web设计器)和Nested Master Page(嵌套母版页)
    [导入]vbs修改注册表
    正则表达式30分钟入门教程
  • 原文地址:https://www.cnblogs.com/liuzongxin/p/15256553.html
Copyright © 2011-2022 走看看