zoukankan      html  css  js  c++  java
  • bzoj2527[Poi2011] Meteors

    题目链接:bzoj2527

    题目大意:

    相当于,有n个人,m个数,每个数分别累加到一个人身上,所以一个人的值等于所有归他的数的和。这m个数按顺序排一个。有k个操作,每个操作则给[l,r]上的数都增加ai,而每个人都有个目标pi。问对于每个人来说,第几个操作后,他的值达到了他的目标。【诶差不多这个意思

    数据范围:1<=n,m,k<=300000


    题解:

    转自http://victorwonder.is-programmer.com/posts/70210.html

    首先,我们需要用一个列表id[]记录所有查询的编号,刚开始的时候,id[]自然是递增的.同时,我们用一个数组cur[i]记录下,第i个国家在l-1场流星雨过后,收集到的陨石的数目。
    主过程为void solve(int head,int tail,int l,int r),表示对于id[head]到id[tail]的所有询问,在[l,r]范围内查询答案,通过上一层的操作,我们保证id[head]到id[tail]的所有询问的答案都在[l,r]范围内。
    首先,我们先模拟[l,mid]这么多次操作(在询问重新划分之后,必须要再次模拟,将数组清空),用树状数组或者是线段树计算出在[l,mid]场流星雨之后,每个空间站收集到的陨石的数目。
    然后我们查询,每个国家收集到的陨石的数目,要注意的是,我们需要用链表储存每个国家对应的空间站,并且一一枚举,用tmp[id[i]]表示国家id[i]收集到的陨石的数目。
    那么从[1,mid]这么多次操作之后,国家id[i]收集到的陨石数目就是tmp[id[i]]+cur[id[i]],如果tmp[id[i]]+cur[id[i]]>p[id[i]],那么表明对于国家id[i],其答案在[l,mid]这个范围内,否则其答案在[mid+1,r]范围内,并将tmp[id[i]]累加到cur[id[i]]上。
    还有一个坑点是,tmp[id[i]]可能很大,会爆掉long long,所以如果枚举一个国家的所有空间站的时候,发现tmp[id[i]]已经大于p[id[i]]了,那么就break好了,不然会出错。
    因为可能会出现怎么也无法满足的情况,所以我们需要多增加一场流星雨,这场流星雨的数量为infi,保证能够让所有国家都满足要求,那么最后,对于所有答案为k+1的询问,输出NIE就行了。
     
    总的来说,整体二分就是将所有询问一起二分,然后获得每个询问的答案。

    这篇写得真的很好(很容易懂)!我的第一道整体二分!模板什么的就是学他的。

    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    #define inf 0x7fffffff
    #define maxn 310000
    typedef long long LL;
    
    struct question
    {
    	int l,r;LL c;
    }q[maxn];
    int m,len,nxt[maxn],first[maxn];
    LL c[maxn],sd[maxn],cur[maxn],tmp[maxn];
    int ans[maxn],tol[maxn],tor[maxn],id[maxn],to[maxn];
    void ins(int x,int y)
    {
    	to[++len]=y;
    	nxt[len]=first[x];
    	first[x]=len;
    }
    int lowbit(int x){return x&(-x);}
    void change(int x,LL k)
    {
    	for (x;x<=m;x+=lowbit(x)) c[x]+=k;
    }
    LL query(int x)
    {
    	LL ret=0;
    	for (x;x>0;x-=lowbit(x)) ret+=c[x];
    	return ret;
    }
    void modify(int x,int y,LL z)
    {
    	change(x,z);
    	change(y+1,-z);
    }
    void solve(int head,int tail,int l,int r)
    {
    	int i,lnum=0,rnum=0;
    	int mid=(l+r)>>1;
    	if (l==r)
    	{
    		for (i=head;i<=tail;i++) ans[id[i]]=l;
    		return;
    	}
    	for (i=l;i<=mid;i++)
    	{
    		if (q[i].l<=q[i].r) modify(q[i].l,q[i].r,q[i].c);
    		else modify(q[i].l,m,q[i].c),modify(1,q[i].r,q[i].c);
    	}
    	for (i=head;i<=tail;i++)
    	{
    		tmp[id[i]]=0;
    		for (int k=first[id[i]];k!=-1;k=nxt[k])
    		{
    			LL now=query(to[k]);
    			tmp[id[i]]+=now;
    			if (tmp[id[i]]+cur[id[i]]>sd[id[i]]) break;
    		}
    		if (tmp[id[i]]+cur[id[i]]>=sd[id[i]]) tol[++lnum]=id[i];
    		else {tor[++rnum]=id[i];cur[id[i]]+=tmp[id[i]];}
    	}
    	for (i=l;i<=mid;i++)
    	{
    		if (q[i].l<=q[i].r) modify(q[i].l,q[i].r,-q[i].c);
    		else modify(q[i].l,m,-q[i].c),modify(1,q[i].r,-q[i].c);
    	}
    	for (i=0;i<lnum;i++) id[head+i]=tol[i+1];
    	for (i=0;i<rnum;i++) id[head+lnum+i]=tor[i+1];
    	solve(head,head+lnum-1,l,mid);
    	solve(head+lnum,tail,mid+1,r);
    }
    int main()
    {
    	//freopen("a.in","r",stdin);
    	//freopen("a.out","w",stdout);
    	int n,i,x,k;
    	scanf("%d%d",&n,&m);len=0;
    	memset(c,0,sizeof(c));
    	memset(first,-1,sizeof(first));
    	for (i=1;i<=m;i++)
    	{
    		scanf("%d",&x);
    		ins(x,i);
    	}
    	for (i=1;i<=n;i++) {scanf("%d",&sd[i]);id[i]=i;}
    	scanf("%d",&k);
    	for (i=1;i<=k;i++)
    	  scanf("%d%d%lld",&q[i].l,&q[i].r,&q[i].c);
    	k++;q[k].l=1;q[k].r=m;q[k].c=inf;
    	solve(1,n,1,k);
    	for (i=1;i<=n;i++) 
    	  if (ans[i]!=k) printf("%d
    ",ans[i]);
    	  else printf("NIE
    ");
    	return 0;
    }



  • 相关阅读:
    【Linux】ZeroMQ 在 centos下的安装
    ZeroMQ下载、编译和使用
    在Linux系统上安装Git
    Linux下python2.7安装pip
    [Tyvj1474]打鼹鼠
    [BZOJ2908]又是nand
    [SPOJ375]Qtree
    浅谈算法——树链剖分
    [BZOJ5368/Pkusc2018]真实排名
    [FJOI2007]轮状病毒
  • 原文地址:https://www.cnblogs.com/Euryale-Rose/p/6527816.html
Copyright © 2011-2022 走看看