zoukankan      html  css  js  c++  java
  • [POI2011]MET-Meteors 题解

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

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

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

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

    具体实现:

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

    细节:

    • 建议一开始将 (R) 设成 (k+1),这样方便判断 (k) 次后还不能满足要求的国家。
    • 可能有多个地方是一个国家掌控的,对于这个国家在第一次就遍历下它所有的领地,记录下答案,之后再遍历到它的领地时直接用这个答案。
    • 对于一个流星雨若 (l_i>r_i),可视为在 (1sim r_i) 加, (r_isim l_i-1) 减,(l_isim 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=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
    ",ans[i]);
    	else printf("NIE
    ");
    }
    
  • 相关阅读:
    leetcode 17 Letter Combinations of a Phone Number
    剑指offer 数字翻译成字符串
    剑指offer 把数组排成最小的数
    剑指offer 整数中1出现的次数(从1到n整数中1出现的次数)
    剑指offer 数据流中的中位数
    RNN, LSTM, GRU cells
    剑指offer 最小的K个数
    PWA-网络
    PWA-缓存
    2018 总结
  • 原文地址:https://www.cnblogs.com/zYzYzYzYz/p/14493428.html
Copyright © 2011-2022 走看看