• [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;
    }
    
  • 相关阅读:
    JavaScript WebSocket C# SuperSocket.WebSocket 示例
    Nginx 配置
    Temporary Post Used For Theme Detection (272f6d70fb8946f3a568afd3d7b053bd 3bfe001a32de4114a6b44005b770f6d7)
    SpringBoot多数据源事务解决方案
    SpringBoot集成mybatis拦截器修改表名
    点击各个按钮,在执行操作之前出现确认提示框
    incoming change和current change
    Expected Number with value 8, got String with value "8".
    正则只能输入数字遇到的问题
    Antd 4.19 Modal + Form;打开modal时使用setFieldsValue,首次回显正常,第二次无效?
  • 原文地址:https://www.cnblogs.com/zhangjianjunab/p/13933663.html
Copyright © 2020-2023  润新知