【[POI2011]MET-Meteors】整体二分+一些神奇优化
洛谷上很早就过了,然而NK上的数据很强,迫不得已重构了两次代码orz,还调整了一下算法。
luogu3752
| P3932Meteors | ||
|
问题描述
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
来源 POI2011
这道题有个十分显然的做法,就是直接套入一个树状差分数组进行整体二分,然后每次加入前mid个,查询,搞完还原树状数组。看上去时间复杂度并没有什么问题,然后,愉快的被卡卡卡卡常(微笑)。
这时候就要用到一个类似于莫队里面的左移右移的东西了。我们可以将下陨石和询问分开看,设定一个类似莫队R的 东西(本题是前缀和没有L),对R跑到当前mid的位置。这样我们可以尝试去画一个图,就会惊讶发现,对于整个整体二分最多每层会移动n次。
看似对时间复杂度影响不大,其实不然,实际上我们反复用了上一次的插入树状数组后的结果,也就是说,我们节省了很多重复的,冗杂的工作,最后写出代码也其实更加精简易懂(不用处理队列类型)。
code:
#include<stdio.h>
#include<bits/stdc++.h>
#define lowbit(x) ((x)&(-x))
using namespace std;
const int maxn = 300005;
int n,m,k;
int bit[maxn];
vector<int>ve[maxn];
void add(int x,int d) { for(;x<=m+2;x+=lowbit(x)) bit[x]+=d; }
int getsum(int x) { int sum=0; for(;x;x-=lowbit(x)) sum+=bit[x]; return sum; }
int ans[maxn];
struct node
{ int id,ned; };
struct chan
{
int l,r,cha;
}z[maxn];
void modify(int po,int knd)
{
if(knd)
{
if(z[po].r>=z[po].l)
{
add(z[po].l,z[po].cha);
add(z[po].r+1,-z[po].cha);
}
else
{
add(1,z[po].cha);
add(z[po].r+1,-z[po].cha);
add(z[po].l,z[po].cha);
}
}
else
{
if(z[po].r>=z[po].l)
{
add(z[po].l,-z[po].cha);
add(z[po].r+1,z[po].cha);
}
else
{
add(1,-z[po].cha);
add(z[po].r+1,z[po].cha);
add(z[po].l,-z[po].cha);
}
}
}
int cur;
void query(vector<node>q,int l,int r)
{
if(!q.size()) return;
if(l==r)
{
int ss = q.size();
for(int i=0;i<ss;i++) ans[q[i].id] = l;
return;
}
int mid = (l+r)/2;
while(cur<mid) ++cur,modify(cur,1);
while(cur>mid) modify(cur,0),--cur;
int ss=q.size();
vector<node>q1,q2;
for(int i=0;i<ss;i++)
{
int x = q[i].id;
int sd = ve[x].size();
int summ = 0;
for(int j=0;j<sd;j++)
{
summ+=getsum(ve[x][j]);
if(summ>=q[i].ned) break;
}
if(summ>=q[i].ned) q1.push_back(q[i]);
else q2.push_back((node){q[i].id,q[i].ned});
}
query(q1,l,mid);
query(q2,mid+1,r);
}
int main()
{
vector<node>q;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
int x;
scanf("%d",&x);
ve[x].push_back(i);
}
for(int i=1;i<=n;i++)
{
int x;
scanf("%d",&x);
q.push_back((node){i,x});
}
scanf("%d",&k);
for(int i=1;i<=k;i++)
{
int ll,rr,aa;
scanf("%d%d%d",&ll,&rr,&aa);
z[i].l = ll ;z[i].r = rr; z[i].cha = aa;
}
++k; z[k].l=1; z[k].r=m; z[k].cha = 0x3f3f3f3f;
query(q,1,k);
for(int i=1;i<=n;i++) if(ans[i]!=k) printf("%d\n",ans[i]);
else printf("NIE\n");
}

浙公网安备 33010602011771号