NKOJ 3932 Meteors (整體二分+樹狀數組)

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


如果只有一個國家,那麼顯然的二分答案,複雜度O(mlogk+klogm) ,用線段樹或樹狀差分數組來維護每個太空站的情況,每次二分後只把兩次二分區間的差的區間信息進行修改,最多修改k次。

考慮多個國家的情況,仍然暴力枚舉每個國家的話,複雜度是O(mlogk+nklogm) ,考慮優化,這時注意到枚舉每個國家時要維護的線段樹其實是一樣的,而主要的時間花費恰好是維護這個線段樹,因此可以考慮整體二分,同樣二分答案,每次判斷每個國家的答案區間,將答案區間在[l,mid] 的國家甩到Q1 裏面,把答案區間在[mid+1,r] 的甩到Q2 中,對Q1 遞歸求解,同時回溯的時候還原線段樹,然後對Q2 遞歸求解,在底層的時候就算出了答案。這樣就只需要維護全局線段樹,而不需要每次二分答案都重新維護線段樹。

總時間複雜度O(mlogklogm+klogklogm)


代碼:

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
#define N 400005
#define ll long long
using namespace std;
struct node
{
    ll v;
    vector<ll>p;
}C[N];
ll cur,id[N],Q1[N],Q2[N],n,m,q,L[N],R[N],A[N],D[N],Ans[N];
void MD(ll x,ll d)
{for(ll i=x;i<=m;i+=(i&-i))D[i]+=d;}
ll GS(ll x)
{
    ll i,sum=0;
    for(i=x;i;i-=(i&-i))sum+=D[i];
    return sum;
}
void CA(ll k,ll ty)
{
    if(L[k]<=R[k])MD(L[k],A[k]*ty),MD(R[k]+1,-A[k]*ty);
    else MD(L[k],A[k]*ty),MD(1,A[k]*ty),MD(R[k]+1,-A[k]*ty);
}
void Solve(ll l,ll r,ll sl,ll sr)
{
    ll i,j,k,x,y,mid=sl+sr>>1;
    if(sl==sr)
    {
        for(i=l;i<=r;i++)if(Ans[id[i]]!=-1)Ans[id[i]]=sl;
        return;
    }
    while(cur<mid)CA(++cur,1);
    while(cur>mid)CA(cur--,-1);
    x=y=0;
    for(i=l;i<=r;i++)
    {
        k=0;
        for(j=0;j<C[id[i]].p.size();j++)
        {
            k+=GS(C[id[i]].p[j]);
            if(k>=C[id[i]].v)break;
        }
        if(k>=C[id[i]].v)Q1[++x]=id[i];
        else Q2[++y]=id[i];
    }
    for(i=1;i<=x;i++)id[l+i-1]=Q1[i];
    for(i=1;i<=y;i++)id[r-i+1]=Q2[y-i+1];
    Solve(l,r-y,sl,mid);
    Solve(l+x,r,mid+1,sr);
}
int main()
{
    ll i,j,k,x,y,z;
    scanf("%lld%lld",&n,&m);
    for(i=1;i<=m;i++)
    {
        scanf("%lld",&x);
        C[x].p.push_back(i);
    }
    for(i=1;i<=n;i++)scanf("%lld",&C[i].v),id[i]=i;
    scanf("%lld",&q);
    for(i=1;i<=q;i++)scanf("%lld%lld%lld",&L[i],&R[i],&A[i]);
    Solve(1,n,1,q+1);
    for(i=1;i<=n;i++)
    if(Ans[i]==q+1)puts("NIE");
    else printf("%lld\n",Ans[i]);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章