ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

[POI2011]MET-Meteors 题解

2021-03-07 08:32:48  阅读:222  来源: 互联网

标签:ch int 题解 POI2011 300010 MET 国家 sim 流星雨


显然答案具有单调性,对于一个国家,如果第 \(mid\) 次后达到了要求,那么对于大于 \(mid\) 的第 \(r\) 次后也肯定达到了要求。

对于单个一个国家,可以二分流星雨的次数。复杂度 \(O(m\log k)\)。

但是对于 \(n\) 个国家的情况,复杂度即为 \(O(nm\log k)\) 很快啊不能满足要求。

这提示我们使用整体二分,把所有国家放在一起二分。

具体实现:

  1. 开 \(n\) 个 vector 记录每个国家有哪些地方。
  2. 对每个位置记录它属于哪个国家,合成一个结构体。
  3. 开始二分 \(L,R,st,ed\) 表示拥有 \(q_{st\sim ed}\) 这些土地的国家在第 \(L\sim R\) 次流星雨后会达到要求。
    1. 如果 \(L=R\) ,记录一下答案,return。
    2. 令 \(M=\lfloor \frac{L+R}{2}\rfloor\),将 \(L\sim M\) 次的流星雨处理一下(用一个树状数组就行了)。
    3. 查询 \(st\sim ed\) 的每个国家是否达到要求,
      1. 若达到,将他放在 \(lq\) 中,意思是这个国家在第 \(L\sim M\) 次流星雨后便会达到要求。
      2. 否则,将它的要求减去这些流星雨的贡献,将他放在 \(rq\) 中。
    4. 清空 \(L\sim M\) 次的流星雨的贡献
    5. 递归处理 \((L,M,lst,led)\),\((M+1,R,rst,red)\)。
  4. 判断是否合法并输出(若不合法,那么它在第 \(k\) 次流星雨和也没达到要求)。

细节:

  • 建议一开始将 \(R\) 设成 \(k+1\),这样方便判断 \(k\) 次后还不能满足要求的国家。
  • 可能有多个地方是一个国家掌控的,对于这个国家在第一次就遍历下它所有的领地,记录下答案,之后再遍历到它的领地时直接用这个答案。
  • 对于一个流星雨若 \(l_i>r_i\),可视为在 \(1\sim r_i\) 加, \(r_i\sim l_i-1\) 减,\(l_i\sim m\) 加。

code:

#include<bits/stdc++.h>
#define LL long long
using namespace std;
bool ks;
int n,m,T,ans[300010];
int Lpos[300010],Rpos[300010],p[300010],a[300010];
LL c[300010],asktemp[300010];
vector<int>have[300010];
struct Q
{int bel,pos;}q[300010],lq[300010],rq[300010];
bool js;
inline int read()
{
	int x=0,w=0;char ch=0;
	while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
	while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return w?-x:x;
}
void change(int x,int y)
{for(;x<=m;x+=x&-x)c[x]+=y;}
LL ask(int x,LL y=0)
{for(;x;x-=x&-x)y+=c[x];return y;}
void calc(int L,int R,int st,int ed)
{
	if(st>ed)return;
	if(L==R){
		for(int i=st;i<=ed;i++)
		ans[q[i].bel]=L;
		return;
	}
	int M=(L+R)>>1,l=0,r=0;
	for(int i=L;i<=M;i++)
	if(Lpos[i]<=Rpos[i]){
		change(Lpos[i],a[i]);
		change(Rpos[i]+1,-a[i]);
	}else{
		change(1,a[i]);
		change(Rpos[i]+1,-a[i]);
		change(Lpos[i],a[i]);
	}
	for(int i=st;i<=ed;i++){
		if(asktemp[q[i].bel]==-1){
			asktemp[q[i].bel]=0;
			for(int j=0;j<int(have[q[i].bel].size());j++){
				asktemp[q[i].bel]+=ask(have[q[i].bel][j]);
				if(asktemp[q[i].bel]>=p[q[i].bel])break;
			}
		}
		if(asktemp[q[i].bel]>=p[q[i].bel])lq[++l]=q[i];
		else rq[++r]=q[i];
	}
	for(int i=L;i<=M;i++)
	if(Lpos[i]<=Rpos[i]){
		change(Lpos[i],-a[i]);
		change(Rpos[i]+1,a[i]);
	}else{
		change(1,-a[i]);
		change(Rpos[i]+1,a[i]);
		change(Lpos[i],-a[i]);
	}
	for(int i=st;i<=ed;i++){
		if(i-st+1<=l)q[i]=lq[i-st+1];
		else{
			q[i]=rq[i-st+1-l];
			if(asktemp[q[i].bel]!=-1)
				p[q[i].bel]-=asktemp[q[i].bel];
		}
		asktemp[q[i].bel]=-1;
	}
	calc(L,M,st,st+l-1);
	calc(M+1,R,st+l,ed);
}
int main()
{
	freopen("test.in","r",stdin);
	freopen("test.out","w",stdout);
	// cout<<(&js-&ks)/1024./1024<<'\n';
	n=read();m=read();
	for(int i=1;i<=m;i++)
		have[q[i].bel=read()].push_back(q[i].pos=i);
	for(int i=1;i<=n;i++)p[i]=read();
	T=read();
	for(int i=1;i<=T;i++)
		Lpos[i]=read(),Rpos[i]=read(),a[i]=read();
	memset(asktemp,-1,sizeof asktemp);
	memset(ans,0x3f,sizeof ans);
	calc(1,T+1,1,m);
	for(int i=1;i<=n;i++)
	if(ans[i]<=T)printf("%d\n",ans[i]);
	else printf("NIE\n");
}

标签:ch,int,题解,POI2011,300010,MET,国家,sim,流星雨
来源: https://www.cnblogs.com/zYzYzYzYz/p/14493428.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有