BZOJ5308: [Zjoi2018]胖

版权声明:...............转载说一声并注明出处qaq............... https://blog.csdn.net/L_0_Forever_LF/article/details/80228714

一个点每被更新一次最短路都会对t贡献1
我们考虑所有和宫殿有边相连的瞭望塔,考虑他能更新到的区间,一定是连续的一段
我们可以二分这一段的左右端点,假设左端点在l,这个瞭望塔在i,那么就是要求[2li,i1]这一段里面没有其他瞭望塔到l的距离比i更优,可以用rmq查

注意多个点到同一个点i距离相同时,可能会重复计算,这时到i边数最小的优先考虑,如果边数最小的有多个时(最多也就2个),固定左侧那个更近

就像题目名字一样….写的很胖….

code:

#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;

inline void read(int &x)
{
    char c; while(!((c=getchar())>='0'&&c<='9'));
    x=c-'0';
    while((c=getchar())>='0'&&c<='9') (x*=10)+=c-'0';
}
const int maxn = 210000;
const int maxd = 20;

int n,m,q;
ll sum[maxn];

struct node
{
    int x,i;
    friend inline bool operator <(const node x,const node y){return x.i<y.i;}
}a[maxn],b[maxn]; int cnt;

struct RMQ
{
    int len[maxn];
    void init()
    {
        for(int i=0;(1<<i)<=n;i++) len[1<<i]=i;
        for(int i=2;i<=n;i++) if(!len[i]) len[i]=len[i-1];
    }
    ll c1[maxn],c2[maxn];
    int mxp[maxn][maxd],mxs[maxn][maxd];
    int mnp[maxn][maxd],mns[maxn][maxd];
    int MX(int x,int y) {return c1[x]>=c1[y]?x:y;}
    int MN(int x,int y) {return c2[x]<=c2[y]?x:y;}
    void generate()
    {
        for(int i=1;i<=cnt;i++) c1[i]=sum[b[i].i]-b[i].x;
        for(int i=1;i<=cnt;i++) c2[i]=b[i].x+sum[b[i].i];

        for(int i=1;i<=cnt;i++) mxp[i][0]=mxs[i][0]=i;
        for(int d=1;(1<<d)<=cnt;d++)
        {
            for(int i=(1<<d);i<=cnt;i++)
                mxp[i][d]=MX(mxp[i-(1<<d-1)][d-1],mxp[i][d-1]);
            for(int i=1;i+(1<<d)-1<=cnt;i++)
                mxs[i][d]=MX(mxs[i][d-1],mxs[i+(1<<d-1)][d-1]);
        }

        for(int i=1;i<=cnt;i++) mnp[i][0]=mns[i][0]=i;
        for(int d=1;(1<<d)<=cnt;d++)
        {
            for(int i=(1<<d);i<=cnt;i++)
                mnp[i][d]=MN(mnp[i-(1<<d-1)][d-1],mnp[i][d-1]);
            for(int i=1;i+(1<<d)-1<=cnt;i++)
                mns[i][d]=MN(mns[i][d-1],mns[i+(1<<d-1)][d-1]);
        }
    }
    ll querymx(int l,int r)
    {
        if(l>r) return -1;
        int L=len[r-l+1];
        return MX(mxs[l][L],mxp[r][L]);
    }
    ll querymn(int l,int r)
    {
        if(l>r) return -1;
        int L=len[r-l+1];
        return MN(mns[l][L],mnp[r][L]);
    }
}rmq;
int fip(int i)
{
    int l=1,r=cnt;
    while(l<=r)
    {
        int mid=l+r>>1;
        if(b[mid].i<=i) l=mid+1;
        else r=mid-1;
    }
    return l-1;
}
int fis(int i)
{
    int l=1,r=cnt;
    while(l<=r)
    {
        int mid=l+r>>1;
        if(b[mid].i>=i) r=mid-1;
        else l=mid+1;
    }
    return r+1;
}
bool judgep(int i,int p)
{
    ll c=b[i].x+sum[b[i].i]-sum[p];

    int pl=max(1,2*p-b[i].i),pr=b[i].i-1,l,r;
    l=fis(pl),r=fip(p); int c1=rmq.querymx(l,r);
    l=fis(p),r=fip(pr); int c2=rmq.querymn(l,r);

    if(c1!=-1&&-rmq.c1[c1]+sum[p]<=c) return false;
    if(c2!=-1&&rmq.c2[c2]-sum[p]<=c) return false;
    return true;
}
bool judges(int i,int p)
{
    ll c=b[i].x+sum[p]-sum[b[i].i];

    int pl=b[i].i+1,pr=min(n,2*p-b[i].i),l,r;
    l=fis(pl),r=fip(p); int c1=rmq.querymx(l,r);
    l=fis(p),r=fip(pr); int c2=rmq.querymn(l,r);

    if(c1!=-1&&-rmq.c1[c1]+sum[p]<=c) return false;
    if(c2!=-1&&rmq.c2[c2]-sum[p]==c&&b[c2].i-p==p-b[i].i) return true;
    if(c2!=-1&&rmq.c2[c2]-sum[p]<=c) return false;
    return true;
}

int main()
{
    read(n); read(q);
    sum[1]=0;
    for(int i=2;i<=n;i++)
    {
        int x; read(x);
        sum[i]=sum[i-1]+x;
    }
    rmq.init();
    while(q--)
    {
        read(m);
        for(int i=1;i<=m;i++) read(a[i].i),read(a[i].x);
        sort(a+1,a+m+1); cnt=0;
        for(int i=1;i<=m;)
        {
            int j=i+1; for(;j<=m&&a[j].i==a[i].i;j++);j--;
            b[++cnt]=a[i];
            for(;i<=j;i++) b[cnt].x=min(b[cnt].x,a[i].x);
        }
        rmq.generate();

        ll ans=0;
        for(int i=1;i<=cnt;i++)
        {
            int l=1,r=b[i].i-1;
            while(l<=r)
            {
                int mid=l+r>>1;
                if(judgep(i,mid)) r=mid-1;
                else l=mid+1;
            }
            ans+=b[i].i-r;

            l=b[i].i+1;r=n;
            while(l<=r)
            {
                int mid=l+r>>1;
                if(judges(i,mid)) l=mid+1;
                else r=mid-1;
            }
            ans+=l-1-b[i].i;
        }
        printf("%lld\n",ans);
    }

    return 0;
}
阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页