zoukankan      html  css  js  c++  java
  • [AH2017/HNOI2017]影魔

    题目

    [AH2017/HNOI2017]影魔

    做法

    做法1(口胡)

    这个做法估计会T

    考虑每个数字连向后面第一个比他大的树,对一个区间建一颗树,对于(i<j<k,a_i<a_j<a_k)的询问,即为树上每个点(dep-2)之和,然后其余类似,用莫队维护,时间复杂度:(O(nsqrt{n})),常数和码量都巨大,于是没有打,膜了题解。

    当然,至于为什么为(dep-2)之和,因为我们默认(i<j<k,a_i<a_j<a_k)是由((i,k))区间中最大的数字来找到这个区间。

    做法2

    以下摘自此博客

    这个题可以采取离线处理的方式.先处理出每个点i左边第一个比它大的点L[i],和右边第一个比它大的点R[i].

    那么对于区间L[i]到R[i]有p1的贡献.①

    对于左端点在L[i]+1到i-1,右端点为R[i]的区间有p2的贡献.②

    对于左端点为L[i],右端点为i+1到R[i]-1的区间也有p2的贡献.③

    所以我们离线排序处理好.

    对于①情况,我们在扫到R[i]时,更新点L[i]的贡献

    对于②情况,我们在扫到R[i]时,更新区间L[i]+1到i-1的贡献

    对于③情况,我们在扫到L[i]时,更新区间i+1到R[i]-1的贡献

    我们对于每个询问[l,r],在扫到l-1时,我们记录此时区间l到r的每个点的贡献和为sum1,然后当我们扫到r的时候,再次记录此时的区间l到r的每个点的贡献和为sum2,显然答案就是sum2-sum1了.

    好,至于为什么吗,我来解释一下,为什么(p1)的贡献只用(L[i],R[i])来统计呢?(当然,这也可以证明(p1)区间个数实在(O(n))级别的)

    1. 为什么每个区间必定会被统计且只会被统计一次:首先,考虑这个((l,r))是个合法的(p1)区间,那么对于((l,r))范围中最大的数字(mid),其(L[i]=l,R[i]=r),且对于这个区间其他数字,绝对不可能(L[i]=l,R[i]=r),因为(mid)比他们都打,卡在中间挡住了他们。
    2. 为什么((L[i],R[i]))一定构成一个合法区间:这不废话?

    对于(p2)(a_i<a_j<a_k),证明方法类似,每个区间由这个区间中最大的数字来统计,(a_{i}>a_{j}>a_{k})

    当然,别忘了((i,i+1))固定有(p1)的贡献。

    时间复杂度:(O(nlogn))

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    #define  N  210000
    #define  NN  410000
    #define  NNN  610000
    using  namespace  std;
    typedef  long  long  LL;
    struct  node
    {
    	int  l,r,d;
    	LL  lazy,c;
    }tr[NN];int  len,last[N];
    inline  void  pushlazy(int  x,LL  k){tr[x].lazy+=k;tr[x].c+=k*tr[x].d;}
    inline  void  updata(int  x){tr[x].c=tr[tr[x].l].c+tr[tr[x].r].c;}
    inline  void  downdata(int  x)
    {
    	if(tr[x].lazy)
    	{
    		pushlazy(tr[x].l,tr[x].lazy);
    		pushlazy(tr[x].r,tr[x].lazy);
    		tr[x].lazy=0;
    	}
    }
    void  bt(int  l,int  r)
    {
    	int  now=++len;tr[now].d=(r-l+1);
    	if(l<r)
    	{
    		int  mid=(l+r)>>1;
    		tr[now].l=len+1;bt(l,mid);
    		tr[now].r=len+1;bt(mid+1,r);
    	}
    }
    void  change(int  now,int  l,int  r,int  ll,int  rr,LL  k)
    {
    	if(l==ll  &&  r==rr){pushlazy(now,k);return  ;}
    	int  mid=(l+r)>>1;
    	downdata(now);
    	if(rr<=mid)change(tr[now].l,l,mid,ll,rr,k);
    	else  if(mid<ll)change(tr[now].r,mid+1,r,ll,rr,k);
    	else  change(tr[now].l,l,mid,ll,mid,k),change(tr[now].r,mid+1,r,mid+1,rr,k);
    	updata(now);
    }
    LL  findans(int  now,int  l,int  r,int  ll,int  rr)
    {
    	if(l==ll  &&  r==rr)return  tr[now].c;
    	int  mid=(l+r)>>1;
    	downdata(now);
    	if(rr<=mid)return  findans(tr[now].l,l,mid,ll,rr);
    	else  if(mid<ll)return  findans(tr[now].r,mid+1,r,ll,rr);
    	else  return  findans(tr[now].l,l,mid,ll,mid)+findans(tr[now].r,mid+1,r,mid+1,rr);	
    }
    int  L[N],R[N],n,m,a[N];
    LL  q1,q2;
    int  sta[N],top;
    struct  Query
    {
    	int  l,r;
    	LL  *id,type;
    };
    struct  CHANGE
    {
    	int  l,r,k,id/*在访问到哪个人时会使用这个*/;
    }ch[NNN];int  clen,cnow=1;
    inline  bool  cmp(CHANGE  x,CHANGE  y){return  x.id<y.id;}
    vector<Query> fuck[N];
    LL  ans[N];
    inline  void  solve(int  x/*加入第x个位置*/)
    {
    	while(cnow<=clen  &&  ch[cnow].id==x)
    	{
    		if(ch[cnow].l<=ch[cnow].r)change(1,1,n,ch[cnow].l,ch[cnow].r,ch[cnow].k);
    		cnow++;
    	}
    	for(int  i=0;i<fuck[x].size();i++)
    	{
    		Query  y=fuck[x][i];
    		(*y.id)+=y.type*findans(1,1,n,y.l,y.r);
    	}
    }
    int  main()
    {
    	scanf("%d%d%d%d",&n,&m,&q1,&q2);
    	for(int  i=1;i<=n;i++)scanf("%d",&a[i]);
    	for(int  i=1;i<=n;i++)
    	{
    		while(top  &&  a[sta[top]]<a[i])top--;
    		L[i]=sta[top];
    		sta[++top]=i;
    	}
    	top=0;
    	for(int  i=n;i>=1;i--)
    	{
    		while(top  &&  a[sta[top]]<a[i])top--;
    		R[i]=sta[top];
    		sta[++top]=i;
    	}
    	for(int  i=1;i<=n;i++)
    	{
    		if(L[i]  &&  R[i])
    		{
    			ch[++clen].id=R[i];ch[clen].k=q1;ch[clen].l=L[i];ch[clen].r=L[i];
    		}
    		if(R[i])
    		{
    			ch[++clen].id=R[i];ch[clen].k=q2;ch[clen].l=L[i]+1;ch[clen].r=i-1;
    		}
    		if(L[i])
    		{
    			ch[++clen].id=L[i];ch[clen].k=q2;ch[clen].l=i+1;ch[clen].r=!R[i]?n:R[i]-1;
    		}
    	}
    	bt(1,n);
    	sort(ch+1,ch+clen+1,cmp);
    	for(int  i=1;i<=m;i++)
    	{
    		int  l,r;scanf("%d%d",&l,&r);
    		ans[i]=(r-l)*q1;
    		Query  x;x.l=l;x.r=r;x.type=-1;x.id=&ans[i];
    		fuck[l-1].push_back(x);
    		x.type=1;x.id=&ans[i];
    		fuck[r].push_back(x);
    	}
    	for(int  i=1;i<=n;i++)
    	{
    		solve(i);
    	}
    	for(int  i=1;i<=m;i++)printf("%lld
    ",ans[i]);
    	return  0;
    }
    
  • 相关阅读:
    Educational Codeforces Round 67 D. Subarray Sorting
    2019 Multi-University Training Contest 5
    Educational Codeforces Round 69 (Rated for Div. 2) E. Culture Code
    Educational Codeforces Round 69 D. Yet Another Subarray Problem
    2019牛客暑期多校训练第六场
    Educational Codeforces Round 68 E. Count The Rectangles
    2019牛客多校第五场题解
    2019 Multi-University Training Contest 3
    2019 Multi-University Training Contest 2
    [模板] 三维偏序
  • 原文地址:https://www.cnblogs.com/zhangjianjunab/p/13933663.html
Copyright © 2011-2022 走看看