• BZOJ2527 [Poi2011]Meteors 【整体二分 + 树状数组】


    题目

    Byteotian Interstellar Union有N个成员国。现在它发现了一颗新的星球,这颗星球的轨道被分为M份(第M份和第1份相邻),第i份上有第Ai个国家的太空站。
    这个星球经常会下陨石雨。BIU已经预测了接下来K场陨石雨的情况。
    BIU的第i个成员国希望能够收集Pi单位的陨石样本。你的任务是判断对于每个国家,它需要在第几次陨石雨之后,才能收集足够的陨石。

    输入格式

    第一行是两个数N,M。
    第二行有M个数,第i个数Oi表示第i段轨道上有第Oi个国家的太空站。
    第三行有N个数,第i个数Pi表示第i个国家希望收集的陨石数量。
    第四行有一个数K,表示BIU预测了接下来的K场陨石雨。
    接下来K行,每行有三个数Li,Ri,Ai,表示第K场陨石雨的发生地点在从Li顺时针到Ri的区间中(如果Li<=Ri,就是Li,Li+1,...,Ri,否则就是Ri,Ri+1,...,m-1,m,1,...,Li),向区间中的每个太空站提供Ai单位的陨石样本。

    输出格式

    N行。第i行的数Wi表示第i个国家在第Wi波陨石雨之后能够收集到足够的陨石样本。如果到第K波结束后仍然收集不到,输出NIE。

    输入样例

    3 5

    1 3 2 1 3

    10 5 7

    3

    4 2 4

    1 3 1

    3 5 2

    输出样例

    3

    NIE

    1

    提示

    1<=n,m,k<=3*10^5
    1<=Pi<=10^9
    1<=Ai<10^9

    题解

    显然我们需要二分每个国家最早到达需求的时刻,但我们不可能每次都从头统计一遍

    那就整体二分就搞定了√

    具体地,每次对一个区间前半的操作进行操作,然后查看当前区间的询问是否满足,不满足就丢到左区间继续查询,否则就减去当前值后丢到右区间继续查询

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<vector>
    #include<cstring>
    #include<algorithm>
    #define lbt(x) (x & -x)
    #define LL long long int
    #define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
    #define REP(i,n) for (int i = 1; i <= (n); i++)
    #define BUG(s,n) for (int i = 1; i <= (n); i++) cout<<s[i]<<' '; puts("");
    using namespace std;
    const int maxn = 300005,maxm = 10000005,INF = 1000000000;
    inline int read(){
    	int out = 0,flag = 1; char c = getchar();
    	while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
    	while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
    	return out * flag;
    }
    int n,m,K,q[maxn],p[maxn],t[maxn],ans[maxn];
    LL S[maxn];
    vector<int> at[maxn];
    struct node{int l,r,v;}e[maxn];
    void add(int u,LL v){while (u <= m) S[u] += v,u += lbt(u);}
    LL query(int u){LL ans = 0; while (u) ans += S[u],u -= lbt(u); return ans;}
    void solve(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]] = l;
    		return;
    	}
    	int mid = l + r >> 1;
    	for (int i = l; i <= mid && i <= K; i++){
    		if (e[i].l <= e[i].r){
    			add(e[i].l,e[i].v);
    			add(e[i].r + 1,-e[i].v);
    		}
    		else {
    			add(1,e[i].v);
    			add(e[i].r + 1,-e[i].v);
    			add(e[i].l,e[i].v);
    		}
    	}
    	int li = L,ri = R;
    	LL tmp;
    	for (int i = L; i <= R; i++){
    		int u = q[i];
    		tmp = 0;
    		for (unsigned int j = 0; j < at[u].size(); j++)
    			tmp += query(at[u][j]);
    		if (tmp < p[u]) p[u] -= tmp,t[ri--] = u;
    		else t[li++] = u;
    	}
    	for (int i = L; i <= R; i++) q[i] = t[i];
    	for (int i = l; i <= mid && i <= K; i++){
    		if (e[i].l <= e[i].r){
    			add(e[i].l,-e[i].v);
    			add(e[i].r + 1,e[i].v);
    		}
    		else {
    			add(1,-e[i].v);
    			add(e[i].r + 1,e[i].v);
    			add(e[i].l,-e[i].v);
    		}
    	}
    	solve(l,mid,L,li - 1); solve(mid + 1,r,ri + 1,R);
    }
    int main(){
    	n = read(); m = read();
    	for (int i = 1; i <= m; i++){
    		int u = read();
    		at[u].push_back(i);
    	}
    	for (int i = 1; i <= n; i++) p[i] = read();
    	K = read();
    	for (int i = 1; i <= K; i++){
    		e[i].l = read();
    		e[i].r = read();
    		e[i].v = read();
    	}
    	for (int i = 1; i <= n; i++) q[i] = i;
    	solve(1,K + 1,1,n);
    	for (int i = 1; i <= n; i++){
    		if (ans[i] == K + 1) puts("NIE");
    		else printf("%d
    ",ans[i]);
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    【win10系统问题】远程桌面登录一次后,第二次登录看不到用户名和密码输入框
    如何更改Arcmap里经纬度小数点后面的位数?
    腾讯视频qlv格式转换MP4普通视频方法
    kettle_Spoon 修改共享DB连接带汉字引发的错误
    AutoCAD2015激活码和密钥
    SQL获取本周,上周,本月,上月第一天和最后一天[注:本周从周一到周天]
    SQL语句 不足位数补0
    c# winform 服务器提交了协议冲突. Section=ResponseStatusLine
    java.net.ProtocolException: Server redirected too many times
    MarkDown空格缩进的方法
  • 原文地址:https://www.cnblogs.com/Mychael/p/8762410.html
Copyright © 2020-2023  润新知