NOI2018湖北省队集训Day4 T1 djq和MZ

题面:
这里写图片描述


得分情况:
40分,写了纯暴力。


正解:
其实 O ( n n log n ) 的做法还挺好想的(然而我在考场上并没有想出来),分块莫队再用线段树维护块中类型的最大值即可。我们要想办法把这个 log n 去掉。经过冷静地分析,我们发现,修改的总次数为 n n ,查询的总次数为 n ,如果我们能够将前者的复杂度降为 O ( 1 ) ,后者的复杂度升为 O ( n ) ,就可以去掉那个 log n 了。
我们先将l和r差很小的答案暴力计算出来,将剩下的询问分块,每个块内按r排序,这样就可以保证右端只增不减,至于左端因为都在一个块内, n 暴力维护即可。


代码:

#include <bits/stdc++.h>
using namespace std;

const int maxn=1e5+100;
const int bs=300;
int n,m,q,a[maxn],b[maxn],blk[maxn],bl[maxn/bs+10],br[maxn/bs+10];
int ql[maxn],qr[maxn],qx[maxn],qy[maxn];
long long bmx[maxn/bs+10],tmp[maxn/bs+10],cnt[maxn],ans[maxn];
vector <int> qq[maxn];

void inc(int x,int y) { cnt[x]+=y;if(cnt[x]>bmx[blk[x]]) bmx[blk[x]]=cnt[x]; }

long long query(int x,int y)
{
    long long nowans=0;
    for(;x<=y&&x!=bl[blk[x]];x++) nowans=max(nowans,cnt[x]);
    for(;x<=y&&y!=br[blk[y]];y--) nowans=max(nowans,cnt[y]);
    for(;x<=y;x=br[blk[x]]+1) nowans=max(nowans,bmx[blk[x]]);
    return nowans;
}

bool cmp(int x,int y)
{
    return qr[x]<qr[y];
}

int main()
{
    scanf("%d%d%d",&n,&m,&q);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    for(int i=1;i<=n;i++) scanf("%d",&b[i]);
    for(int i=0;i<=maxn-1;i++)
    {
        blk[i]=i/bs;
        if(!bl[i/bs]) bl[i/bs]=i;
        br[i/bs]=i;
    }
    for(int i=1;i<=q;i++)
    {
        scanf("%d%d%d%d",&ql[i],&qr[i],&qx[i],&qy[i]);
        if(qr[i]-ql[i]+1<=bs)
        {
            memset(bmx,0,sizeof(bmx));
            for(int j=ql[i];j<=qr[i];j++) inc(a[j],b[j]);
            ans[i]=query(qx[i],qy[i]);
            for(int j=ql[i];j<=qr[i];j++) cnt[a[j]]-=b[j];
        }
        else qq[blk[ql[i]]].push_back(i);
    }
    for(int i=0;i<maxn;i++)
    {
        if(!qq[i].size()) continue;
        sort(qq[i].begin(),qq[i].end(),cmp);
        int last=br[i];
        memset(cnt,0,sizeof(cnt));memset(bmx,0,sizeof(bmx));
        for(int j=0;j<qq[i].size();j++)
        {
            int x=qq[i][j];
            while(last<qr[x])
            {
                last++;
                inc(a[last],b[last]);
            }
            for(int k=0;k<maxn/bs+10;k++) tmp[k]=bmx[k];
            for(int k=ql[x];k<=br[i];k++) inc(a[k],b[k]);
            ans[x]=query(qx[x],qy[x]);
            for(int k=ql[x];k<=br[i];k++) cnt[a[k]]-=b[k];
            for(int k=0;k<maxn/bs+10;k++) bmx[k]=tmp[k];
        }
    }
    for(int i=1;i<=q;i++) printf("%lld\n",ans[i]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_39662197/article/details/80424625