WC 2011 joy

此题神矣。。。一开始我先想的第二问。。。想到一个线段树做法。。。对于最优子序列的下标序列,i[2k]~i[2k+1]这段区间选一个最小值位置为pos再在pos~i[2k+1]选一个最大值,更新答案。。。再同样处理剩下的区间i[2k]~pos-1。。。数据随机的话O(lognlogn)但是。。。第一问的更新就成了瓶颈。。。

后来看了题解才知道。。。不能把i[2k]~i[2k+1]分为一组。。。要把i[2k-1]~i[2k]分为一组。。。第一问更新用差值。。。即设d[i]=u[i]-u[i-1],这样更新就只需更新最多2个点。。。

题解上细节错误太多了。。。但是想法是很明了的。。。由于把i[2k-1]~i[2k]分为一组。。。对于调整i[2k]~i[2k+1],即将d数组上对应负区间上操作,我们在d数组上建立线段树,查询sum和max就可以了。。。至于区间可操作性。。。只要不包含d[2]或d[n]即可。。。

这样一颗zkw线段树维护d数组。。。一颗splay维护所有负区间左右端点(包括不可操作区间)。。。一颗splay维护可操作负区间可贡献的权值。。。为了不使自己写迷糊了。。。将以上写成class或struct就可以了。。。11kb很好(不要被吓到了。。。只不过缩进很长而已。。。还有一些注释)。。。根本用不到那么多数据结构。。。有一点注意要时刻判断你在splay中查找到的值。。。以及zkw的修改和splay的修改的先后。。。

Code:总时间十个Case7.5S,标程9S+。。。双旋splay果然强大。。。

#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
typedef long long ll;
const ll oo=1000000000;
class splayinter
{
private:
  int rfs,rffs,rch,fs,ffs,root,size;
  bool p,q;
  int f[200005],son[200005][2],keyl[200005],keyr[200005];
  inline void rotate(int s,bool t)
  {
    rfs=f[s],rffs=f[rfs],rch=son[s][t^1];
    if (rffs)
      if (son[rffs][0]==rfs) son[rffs][0]=s; else son[rffs][1]=s;
    f[s]=rffs;
    son[s][t^1]=rfs;
    f[rfs]=s;
    son[rfs][t]=rch;
    if (rch) f[rch]=rfs;
  }
  inline void splay(int s)
  {
    if (!s) return;
    fs=f[s],ffs=f[fs];
    while (fs && (son[fs][0]==s || son[fs][1]==s))
      {
	if (ffs && (son[ffs][0]==fs || son[ffs][1]==fs))
	  {
	    p=(son[ffs][1]==fs);
	    q=(son[fs][1]==s);
	    if (p==q)
	      rotate(fs,p),rotate(s,q);
	    else
	      rotate(s,q),rotate(s,p);
	  }
	else
	  if (son[fs][0]==s) rotate(s,0); else rotate(s,1);
	fs=f[s],ffs=f[fs];
      }
    root=s;
  }
public:
  inline void effectkey(int pos,int &l,int &r)
  {
    l=keyl[pos];
    r=keyr[pos];
  }
  inline int find(int key)
  {
    int now=root,last=0;
    while (now)
      {
	last=now;
	if ((keyl[now]<=key)&&(key<=keyr[now])) return now;
	if (key<keyl[now]) now=son[now][0]; else now=son[now][1];
      }
    while (key<keyl[last]) last=f[last];
    return last;
  }
  inline int find(int kl,int kr)
  {
    int now=root,last=0;
    while (now)
      {
	last=now;
	if ((keyl[now]<=kl)&&(kr<=keyr[now])) return now;
	if (kr<keyl[now]) now=son[now][0]; else now=son[now][1];
      }
    while (kr<keyl[last]) last=f[last];
    return last;
  }
  inline int findleft(int pos)
  {
    while (son[pos][0])
      pos=son[pos][0];
    return pos;
  }
  inline void insert(int kl,int kr)
  {
    if (kr<kl) return;
    int pos=find(kl,kr);
    if (!pos) return;
    splay(pos);
    int ch=son[pos][1];
    son[pos][1]=++size;
    f[size]=pos;
    keyl[size]=kl;
    keyr[size]=kr;
    son[size][1]=ch;
    if (ch) f[ch]=size;
  }
  inline void eraser(int pos)
  {
    if (!pos) return;
    splay(pos);
    int tmpch=son[pos][1];
    if (!tmpch)
      {
	root=son[pos][0];
	f[root]=0;
	son[pos][0]=keyl[pos]=keyr[pos]=0;
      }
    else
      {
	f[tmpch]=0;
	root=tmpch;
	son[pos][1]=0;
	int left=findleft(tmpch);
	splay(left);
	son[left][0]=son[pos][0];
	if (f[son[pos][0]]) f[son[pos][0]]=left;
	son[pos][0]=keyl[pos]=keyr[pos]=0;
      }
  }
  inline void eraser(int kl,int kr)
  {
    if (kr<kl) return;
    int pos=find(kl,kr);
    if (keyl[pos]!=kl || keyr[pos]!=kr) return;
    eraser(pos);
  }
  inline void creat()
  {
    root=1;
    size=1;
    memset(keyl,0,sizeof(keyl));
    memset(keyr,0,sizeof(keyr));
    memset(f,0,sizeof(f));
    memset(son,0,sizeof(son));
    keyl[1]=keyr[1]=1;
    rfs=rffs=rch=fs=ffs=0;
    p=q=0;
  }
} splayi;
class splayval
{
private:
  int rfs,rffs,rch,fs,ffs,root,size;
  bool p,q;
  int f[200005],son[200005][2],sums[200005];
  ll val[200005],totv[200005];
  inline void update(int s)
  {
    sums[s]=sums[son[s][0]]+sums[son[s][1]]+1;
    totv[s]=totv[son[s][0]]+totv[son[s][1]]+val[s];
  }
  inline void rotate(int s,bool t)
  {
    rfs=f[s],rffs=f[rfs],rch=son[s][t^1];
    if (rffs)
      if (son[rffs][0]==rfs) son[rffs][0]=s; else son[rffs][1]=s;
    f[s]=rffs;
    son[s][t^1]=rfs;
    f[rfs]=s;
    son[rfs][t]=rch;
    if (rch) f[rch]=rfs;
    update(rfs);
  }
  inline void splay(int s)
  {
    if (!s) return;
    fs=f[s],ffs=f[fs];
    while (fs && (son[fs][0]==s || son[fs][1]==s))
      {
	if (ffs && (son[ffs][0]==fs || son[ffs][1]==fs))
	  {
	    p=(son[ffs][1]==fs);
	    q=(son[fs][1]==s);
	    if (p==q)
	      rotate(fs,p),rotate(s,q);
	    else
	      rotate(s,q),rotate(s,p);
	  }
	else
	  if (son[fs][0]==s) rotate(s,0); else rotate(s,1);
	fs=f[s],ffs=f[fs];
      }
    root=s;
    update(s);
  }
public:
  inline int find(ll key)
  {
    int now=root,last=0;
    while (now)
      {
	last=now;
	if (val[now]==key) return now;
	if (key<val[now]) now=son[now][0]; else now=son[now][1];
      }
    while (key<val[last]) last=f[last];
    return last;
  }
  inline int findleft(int pos)
  {
    while (son[pos][0])
      pos=son[pos][0];
    return pos;
  }
  inline int mintime(ll key)
  {
    if (totv[root]<key) return -1;
    int now=root,ans=0;
    while (now && (key>0))
      {
	if (totv[son[now][1]]>=key)
	  now=son[now][1];
	else
	  if (totv[son[now][1]]+val[now]>=key) return ans+sums[son[now][1]]+1;
	else
	  {
	    ans+=(sums[son[now][1]]+1);
	    key-=(totv[son[now][1]]+val[now]);
	    now=son[now][0];
	  }
      }
    return ans;
  }
  inline void insert(ll va)
  {
    if (va<0) return;
    int pos=find(va);
    if (!pos) return;
    splay(pos);
    int ch=son[pos][1];
    son[pos][1]=++size;
    val[size]=va;
    f[size]=pos;
    son[size][1]=ch;
    if (ch) f[ch]=size;
    update(size);
    update(pos);
  }
  inline void eraserpos(int pos)
  {
    if (!pos) return;
    splay(pos);
    int tmpch=son[pos][1];
    if (!tmpch)
      {
	root=son[pos][0];
	f[root]=0;
	son[pos][0]=son[pos][1]=val[pos]=totv[pos]=sums[pos]=0;
      }
    else
      {
	f[tmpch]=0;
	son[pos][1]=0;
	root=tmpch;
	int left=findleft(tmpch);
	splay(left);
	son[left][0]=son[pos][0];
	if (son[pos][0]) f[son[pos][0]]=left;
	son[pos][0]=val[pos]=totv[pos]=sums[pos]=0;
	update(left);
      }
  }
  inline void eraserkey(ll va)
  {
    int pos=find(va);
    if ((!pos)||(va!=val[pos])) return;
    eraserpos(pos);
  }
  inline void creat()
  {
    root=1;
    size=1;
    memset(val,0,sizeof(val));
    memset(f,0,sizeof(f));
    memset(son,0,sizeof(son));
    memset(sums,0,sizeof(sums));
    memset(totv,0,sizeof(totv));
    rfs=rffs=rch=fs=ffs=0;
    p=q=0;
  }
} splayv;
class zkwinter
{
private:
  ll maxt[262149],sumt[262149];
  int mm;
  inline ll max(ll a,ll b)
  {
    if (a>b) return a;
    return b;
  }
public:
  inline ll askval(int l,int r)
  {
    l=l+mm-1;
    r=r+mm+1;
    ll ans1=0;
    ll ans2=-oo;
    while (l^r^1)
      {
	if (!(l&1)) 
	  {
	    ans1+=sumt[l^1];
	    if (maxt[l^1]>ans2) ans2=maxt[l^1];
	  }
	if (r&1) 
	  {
	    ans1+=sumt[r^1];
	    if (maxt[r^1]>ans2) ans2=maxt[r^1];
	  }
	l>>=1;
	r>>=1;
      }
    return ans1-ans2;
  }
  inline void modify(int pos,ll val)
  {
    pos+=mm;
    maxt[pos]+=val;
    sumt[pos]+=val;
    pos>>=1;
    while (pos)
      {
	maxt[pos]=max(maxt[pos<<1],maxt[(pos<<1)+1]);
	sumt[pos]+=val;
	pos>>=1;
      }
  }
  inline void creat(ll *a,int n)
  {
    memset(maxt,0,sizeof(maxt));
    memset(sumt,0,sizeof(sumt));
    mm=1<<(int)(log2(n)+1);
    while (mm<n) mm<<1;
    maxt[mm]=-oo;
    for (int i=1;i<=n;i++) maxt[i+mm]=sumt[i+mm]=a[i];
    maxt[mm+1]=-oo;
    for (int i=n+1+mm;i<=(mm<<1);i++) maxt[i]=-oo;
    for (int i=mm-1;i>=1;i--) maxt[i]=max(maxt[i<<1],maxt[(i<<1)+1]),
				sumt[i]=sumt[i<<1]+sumt[(i<<1)+1];
  }
} zkw;
ll a[100005],b[100005],positive=0;
int task=0,q=0,n=0;
inline void init()
{
  scanf("%d%d",&n,&q);
  int i=0;
  for (i=1;i<=n;i++)
    scanf("%I64d",&a[i]);
  int l=0,r=-1;
  for (i=2;i<=n;i++) b[i]=a[i]-a[i-1];
  zkw.creat(b,n);
  for (i=2;i<=n;i++)
    if (b[i]>0)
      {
	positive+=b[i];
	if (r-l>=0)
	  {
	    splayi.insert(l,r);
	    if ((l!=2)&&(r!=n)) splayv.insert(-zkw.askval(l,r));
	    l=0,r=-1;
	  }
      }
    else
      {
	if ((b[i-1]>0) || (i==2)) l=i,r=i-1;
	r++;
      }
  if (b[n]<0)
    if (r-l>=0)
      splayi.insert(l,r);
}
inline void add(int pos,ll val)
{
  ll last=b[pos];
  b[pos]+=val;
  ll now=b[pos];
  if (last>0)
    if (now>0)
      {
	positive+=val;
	zkw.modify(pos,val);//Case 1
      }
    else
      {
	positive-=last;
	int nl=pos,nr=pos;
	if (b[pos-1]<0)
	  {
	    int inter=splayi.find(pos-1),interl=0,interr=0;
	    splayi.effectkey(inter,interl,interr);
	    splayi.eraser(inter);
	    if (interl!=2) splayv.eraserkey(-zkw.askval(interl,interr));
	    nl=interl;
	  }
	if (b[pos+1]<0)
	  {
	    int inter=splayi.find(pos+1),interl=0,interr=0;
	    splayi.effectkey(inter,interl,interr);
	    splayi.eraser(inter);
	    if (interr!=n) splayv.eraserkey(-zkw.askval(interl,interr));
	    nr=interr;
	  }
	zkw.modify(pos,val);
	splayi.insert(nl,nr);
	if ((nl!=2)&&(nr!=n)) splayv.insert(-zkw.askval(nl,nr));
	//Case 4
      }
  else
    if (now>0)
      {
	positive+=now;
	int inter=splayi.find(pos),interl=0,interr=0;
	splayi.effectkey(inter,interl,interr);
	splayi.eraser(inter);
	if ((interl!=2)&&(interr!=n))
	  splayv.eraserkey(-zkw.askval(interl,interr));
	zkw.modify(pos,val);
	int l1=interl,r1=pos-1,l2=pos+1,r2=interr;
	if (l1<=r1)
	  {
	    splayi.insert(l1,r1);
	    if (l1!=2) splayv.insert(-zkw.askval(l1,r1));
	  }
	if (l2<=r2)
	  {
	    splayi.insert(l2,r2);
	    if (r2!=n) splayv.insert(-zkw.askval(l2,r2));
	  }
	//Case 3
      }
    else
      {
	int inter=splayi.find(pos),interl=0,interr=0;
	splayi.effectkey(inter,interl,interr);
	if ((interl<=2)||(interr==n))
	  {
	    zkw.modify(pos,val);
	    return;
	  }
	int nowsum=-zkw.askval(interl,interr);
	splayv.eraserkey(nowsum);
	zkw.modify(pos,val);
	splayv.insert(-zkw.askval(interl,interr));//Case 2
      }
}
inline void prepare()
{
  memset(a,0,sizeof(a));
  memset(b,0,sizeof(b));
  splayi.creat();
  splayv.creat();
  positive=0;
  n=q=0;
}
int main()
{
  freopen("joy.in","r",stdin);
  freopen("joy.out","w",stdout);
  int operch=0,l=0,r=0;
  ll c=0;
  for (scanf("%d",&task);task;task--)
    {
      prepare();
      init();
      for (;q;q--)
	{
	  scanf("%d",&operch);
	  if (operch==0)
	    {
	      scanf("%d%d%I64d",&l,&r,&c);
	      if (l!=1) add(l,c);
	      if (r!=n) add(r+1,-c);
	    }
	  else
	    printf("%I64d %d\n",positive,splayv.mintime(positive));
	}
    }
  return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值