zjoi[ZJOI2018]胖

喜夏-厌秋 提交于 2020-11-21 06:12:34

题解:

因为n,m很大

所以复杂度应该是和m相关的

考虑到每个点的影响区间是连续的

就很简单了

区间查询最小值线段树维护(st表也可以)

然后注意一下不要重复算一个就可以了

max函数用template<class T> 不能与原来min重名

代码:

 

#pragma GCC optimize(2)
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define IL inline
#define rint register int
#define rep(i,h,t) for (rint i=h;i<=t;i++)
#define dep(i,t,h) for (rint i=t;i>=h;i--)
const int N=3e5;
const ll INF=1e18; 
const int N2=1e7; 
ll dis[N],sum1[N],sum2[N];
int n,m,cnt;
struct re{
  int a;
  ll b;
};
vector<int> ve;
ll data1[N2],data2[N2];
int ls[N2],rs[N2];
char ss[1<<27],*A=ss,*B=ss;
IL char gc()
{
  return (A==B&&(B=(A=ss)+fread(ss,1,1<<24,stdin),A==B)?EOF:*A++); 
}
template<class T>void read(T &x)
{
  rint f=1,c; while (c=gc(),c<48||c>57) if (c=='-') f=-1; x=c^48;
  while (c=gc(),47<c&&c<58) x=(x<<3)+(x<<1)+(c^48); x*=f;
}
char sr[1<<24],z[20]; int C=-1,Z;
template <class T> void wer(T x)
{
  if (x<0) sr[++C]='-',x=-x;
  while (z[++Z]=x%10+48,x/=10);
  while (sr[++C]=z[Z],--Z); sr[++C]='\n';
}
template<class T> T MAX(T x,T y)
{
  if (x>y) return(x); else return(y);
}
template<class T> T MIN(T x,T y)
{
  if (x<y) return(x); else return(y);
}
IL void swap(int &x,int &y)
{
  int tmp=x; x=y; y=tmp;
}
void clear()
{
  cnt=0;
  for (int i=0;i<ve.size();i++)
  {
    int x=ve[i];
    data1[x]=INF; data2[x]=INF; ls[x]=0; rs[x]=0;
  }
  ve.clear();
}
void updata(int x)
{
  data1[x]=MIN(data1[ls[x]],data1[rs[x]]);
  data2[x]=MIN(data2[ls[x]],data2[rs[x]]);
}
void change(int &x,int h,int t,int pos,ll k)
{
  if (!x) x=++cnt;
  ve.push_back(x);
  if (h==t)
  {
    data1[x]=MIN(data1[x],sum1[pos-1]+k);
    data2[x]=MIN(data2[x],sum2[pos]+k);
    return;
  }
  int mid=(h+t)/2;
  if (pos<=mid) change(ls[x],h,mid,pos,k);
  else change(rs[x],mid+1,t,pos,k);
  updata(x);
}
ll query1(int x,int h,int t,int h1,int t1)
{
  if (!x) return(INF);
  if (h1<=h&&t<=t1) return(data1[x]);
  ll ans=INF;
    int mid=(h+t)/2;
  if (h1<=mid) ans=query1(ls[x],h,mid,h1,t1);
  if (mid<t1) ans=MIN(ans,query1(rs[x],mid+1,t,h1,t1));
  return(ans);
}
ll query2(int x,int h,int t,int h1,int t1)
{
  if (!x) return(INF);
  if (h1<=h&&t<=t1) return(data2[x]);
  ll ans=INF;
    int mid=(h+t)/2;
  if (h1<=mid) ans=query2(ls[x],h,mid,h1,t1);
  if (mid<t1) ans=MIN(ans,query2(rs[x],mid+1,t,h1,t1));
  return(ans);
}
IL ll check1(int h,int t,int x)
{
  h=MAX(h,1); t=MIN(t,n);
  return(query2(1,1,n,h,t)-sum2[x]);
}
IL ll check2(int h,int t,int x)
{
  h=MAX(h,1); t=MIN(t,n);
  return(query1(1,1,n,h,t)-sum1[x-1]);
}
int main()
{
  read(n); read(m);
  rep(i,1,n-1) read(dis[i]);
  rep(i,1,n-1) sum1[i]=dis[i],sum1[i]+=sum1[i-1];
  dep(i,n-1,1) sum2[i]=dis[i],sum2[i]+=sum2[i+1];
  rep(i,0,N2-1) data1[i]=INF,data2[i]=INF;
  rep(i,1,m)
  {
    int x,y;
    ll ans=0,z;
    read(x);
    vector<re> ve1;
    ve1.push_back((re){0,0});
    clear();
    int root=0;
    rep(j,1,x)
    {
      read(y); read(z);
      change(root,1,n,y,z);
      ve1.push_back((re){y,z});
    }
    rep(j,1,x)
    {
      int y=ve1[j].a;
      ll z=ve1[j].b;
      int h=y,t=n;
      while (h<t)
      {
        int mid=(h+t+1)/2;
        ll jl=sum1[mid-1]-sum1[y-1]+z;
        if (MIN(check1(y+1,mid,mid),check2(mid,2*mid-y-1,mid))>jl&&
           check2(2*mid-y,2*mid-y,mid)>=jl) h=mid;
        else t=mid-1;
      }
      ans+=t-y;
      h=1,t=y;
      while (h<t)
      {
        int mid=(h+t)/2;
        ll jl=sum1[y-1]-sum1[mid-1]+z;
        if (MIN(check2(mid,y-1,mid),check1(2*mid-y+1,mid,mid))>jl&&
            check1(2*mid-y,2*mid-y,mid)>jl) t=mid;
        else h=mid+1;
      }
      ans+=y-h+1;
    }
    wer(ans);
  }
  fwrite(sr,1,C+1,stdout);
  return 0;
}

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!