2019牛客多校第二场

A.Eddy Walker

蒙特卡洛+猜答案
注意答案要累乘

H.Second Large Rectangle

最大的可以用 R M Q RMQ RMQ
然后挖掉四个角分别再做一次即可

J.Subarray

挂一下大佬的链接
https://www.cnblogs.com/FST-stay-night/p/11218660.html
最重要的是学会了前缀和查询相差为 1 1 1的时候的奇技淫巧

#include
#include
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
#define N 10000005
#define left lt
#define right rt
using namespace std;
int n,i,j,limit,base,left,right,num,delta,mn,mx,t;
long long res;
int l[N/10+5],r[N/10+5],f[N],g[N],sum[N*3],b[N*3],c[N*3];
int main()
{
    cin>>n;
    fo(i,1,n) scanf("%d%d",&l[i],&r[i]);
     
    f[1] = r[1] - l[1] + 1;
    fo(i,2,n) f[i] = max(0,f[i-1]-(l[i]-r[i-1]-1)) + r[i] - l[i] + 1;
    g[n] = r[n] - l[n] + 1;
    fd(i,n-1,1) g[i] = max(0,g[i+1]-(l[i+1]-r[i]-1)) + r[i] - l[i] + 1;
     
    i = 1; limit = 1000000000 - 1;
    base = 10000000; //-1e7~1e7 base = 1e7
    while (i <= n)
    {
        j = i;
        while (j+1 <= n && f[j]+g[j+1]>=l[j+1]-r[j]-1) j++;
        left = l[i] - g[i]; if (left < 0) left = 0;
        right = r[j] + f[j]; if (right > limit) right = limit;
         
        num = i; sum[0] = 0; mx = 0; mn = limit+1;
        fo(i,left,right)
        {
            delta = i-left+1;
            if (i >= l[num] && i <= r[num])
                sum[delta] = sum[delta-1] + 1;
            else
                sum[delta] = sum[delta-1] - 1;
            if (i == r[num]) num++;
             
            mn = min(mn,sum[delta]+base);
            mx = max(mx,sum[delta]+base);
            b[sum[delta]+base]++;
            if (sum[delta] > 0) res++;
        }
         
        fd(i,mx-1,mn) b[i] += b[i+1];
        fo(i,left,right)
        {
            delta = i-left+1; t = sum[delta] + base;
            b[t+1] -= c[t+1];
            res += b[t+1];
            c[t] += c[t+1] + 1;
            c[t+1] = 0;
        }
        fo(i,mn,mx) b[i] = c[i] = 0;
        i = j + 1;
    }
    cout<<res<<endl;
    return 0;
}

你可能感兴趣的:(牛客多校)