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

    [AH2017/HNOI2017]影魔 题解

    题意

    (~~~~) 给出长为 (n) 的排列 ({k}) ,共 (m) 次给出 ([a,b]) ,求:

    [sum_{i=a}^bsum_{j=i+1}^b [k_i>k_s land k_j>k_s] imes p_1 +[k_i<k_s<k_j lor k_i>k_s>s_j] imes p_2 (k_s=max_{l=i+1}^{j-1} {k_l}) ]

    题解

    本文版权归Azazel与博客园共有,欢迎转载,但需保留此声明,并给出原文地址,谢谢合作。

    原文地址:https://www.cnblogs.com/Azazel/p/14964757.html

    (~~~~) 考虑处理出每个位置 (i) 左边第一个比它大的数的位置 (L_i) 和右边第一个比它大的数的位置 (R_i) 。则考虑某个位置上的数作为中间最大值(即题意中 (k_s)) 时可以使得哪些区间产生贡献。

    (~~~~) 对于 (p_1) 类的贡献,则此时仅有区间 ([L_i,R_i]) 会以 (i) 作为 (S) 产生 (p_1) 贡献。当区间继续扩大时最大值不是 (k_i) ,当区间缩小时无法满足 (k_l>k_s) ,故仅有该区间满足条件。

    (~~~~) 对于 (p_2) 类的贡献,则所有满足 (lin[L_i+1,i-1],r=R_i)(l=L_i,rin[i+1,R]) 的区间 ([l,r]) 均会产生 (p_2) 的贡献,区间不漏的原因同上。

    (~~~~) 因此,现在从左往右扫一遍 (n) ,对于 (p_1) 类的贡献,当扫到一个 (R_i) 时,将其对应的 (L_i) 贡献加上 (p_1) ,并将 ([L_i+1,i-1]) 的贡献加上 (p_2) ,扫到一个 (L_i) 时,将 ([i+1,R_i]) 的贡献加上 (p_2) 。并将所有询问拆成两个,在 (l-1) 处时得到 ([l,r]) 的总贡献为 (sum_1) ,在 (r) 处时再得到 ([l,r]) 的总贡献为 (sum_2) ,则显然区间 ([l,r]) 本身的答案为 (sum_2-sum_1)

    代码

    查看代码
    #include <cstdio>
    #include <vector>
    #include <algorithm>
    #define ll long long
    using namespace std;
    int n,m,p1,p2;
    int sta[200005],top,arr[200005];
    int L[200005],R[200005];
    int ls[200005],rs[200005];
    ll Ans[200005];
    struct node{
    	int id,l,r;
    	node(){}
    	node(int Id,int L,int R){id=Id,l=L,r=R;}
    };
    struct Range{
    	int l,r,val;
    	Range(){}
    	Range(int L,int R,int Val){l=L,r=R,val=Val;}
    };
    vector <Range> op[200005];
    vector <node> Post[200005],Nega[200005];
    void dfs(int u)
    {
    	if(ls[u])
    	{
    		L[ls[u]]=L[u];
    		R[ls[u]]=u-1;
    		dfs(ls[u]);
    	}
    	if(rs[u])
    	{
    		L[rs[u]]=u+1;
    		R[rs[u]]=R[u];
    		dfs(rs[u]);
    	}
    }
    void Pre()
    {
    	for(int i=1;i<=n;i++)
    	{
    		int k=top;
    		while(k&&arr[sta[k]]<arr[i]) k--;
    		if(k) rs[sta[k]]=i;
    		if(k<top) ls[i]=sta[k+1];
    		sta[++k]=i;top=k;
    	}
    	L[sta[1]]=1,R[sta[1]]=n;
    	dfs(sta[1]);
    }
    struct SegmentTree{
    	#define ls p<<1
    	#define rs p<<1|1
    	#define lson p<<1,l,mid
    	#define rson p<<1|1,mid+1,r
    	ll tr[800005],tag[800005];
    	void pushUp(int p){tr[p]=tr[ls]+tr[rs];}
    	void pushDown(int p,int l,int r)
    	{
    		if(!tag[p]) return;
    		int mid=(l+r)>>1;
    		tr[ls]+=tag[p]*(mid-l+1);
    		tr[rs]+=tag[p]*(r-mid);
    		tag[ls]+=tag[p];tag[rs]+=tag[p];
    		tag[p]=0;
    		return;
    	}
    	void Modify(int p,int l,int r,int lx,int rx,int val)
    	{
    		if(rx<lx) return;
    		if(lx<=l&&r<=rx)
    		{
    			tag[p]+=val;
    			tr[p]+=1ll*(r-l+1)*val;
    			return;
    		}
    		pushDown(p,l,r);
    		int mid=(l+r)>>1;
    		if(lx<=mid) Modify(lson,lx,rx,val);
    		if(mid<rx)  Modify(rson,lx,rx,val);
    		pushUp(p);
    	}
    	ll Query(int p,int l,int r,int lx,int rx)
    	{
    		if(rx<lx) return 0;
    		if(lx<=l&&r<=rx) return tr[p];
    		int mid=(l+r)>>1;ll ret=0;
    		pushDown(p,l,r);
    		if(lx<=mid) ret+=Query(lson,lx,rx);
    		if(mid<rx)  ret+=Query(rson,lx,rx);
    		return ret;
    	}
    }Seg;
    template<typename T>void read(T &x)
    {
        T f=1;x=0;char s=getchar();
        while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
        while(s>='0'&&s<='9') {x=x*10+s-'0';s=getchar();}
        x*=f;
    }
    int main() {
    	read(n);read(m);read(p1);read(p2);
    	arr[0]=arr[n+1]=n+1;
    	for(int i=1;i<=n;i++) read(arr[i]);
    	Pre();
    	for(int i=1;i<=n;i++)
    	{
    		L[i]--,R[i]++;
    		if(1<=L[i]&&R[i]<=n)  op[R[i]].push_back(Range(L[i],L[i],p1));
    		if(L[i]+1<i&&R[i]<=n) op[R[i]].push_back(Range(L[i]+1,i-1,p2));
    		if(1<=L[i]&&R[i]>i+1) op[L[i]].push_back(Range(i+1,R[i]-1,p2));
    	}
    	for(int i=1,l,r;i<=m;i++)
    	{
    		read(l);read(r);Ans[i]+=(r-l)*p1;
    		Nega[l-1].push_back(node(i,l,r));
    		Post[r].push_back(node(i,l,r));
    	}
    	for(int i=0;i<=n+1;i++)
    	{
    		for(int j=0;j<op[i].size();j++)
    		{
    			Range Op=op[i][j];
    			Seg.Modify(1,0,n+1,Op.l,Op.r,Op.val);
    		}
    		for(int j=0;j<Nega[i].size();j++)
    		{
    			node Op=Nega[i][j];
    			Ans[Op.id]-=Seg.Query(1,0,n+1,Op.l,Op.r);
    		}
    		for(int j=0;j<Post[i].size();j++)
    		{
    			node Op=Post[i][j];
    			Ans[Op.id]+=Seg.Query(1,0,n+1,Op.l,Op.r);
    		}
    	}
    	for(int i=1;i<=m;i++) printf("%lld
    ",Ans[i]);
    	return 0;
    }
    ​```
    </details>
  • 相关阅读:
    react中关于render渲染次数的性能优化
    ES6中六种常用的传出调用方式
    在Vue-cli中得xxx.vue文件中快速生成组件模板
    如何在Vue-cli中关闭ESLint以及关闭部分ESLint验证
    使用ES6删除对象中某些属性
    React中使用遍历
    git commit报错解决,绕过代码检查
    React学习——子组件给父组件传值
    React学习——通过模态框中的表单,学习父子组件之间传值
    学习axios
  • 原文地址:https://www.cnblogs.com/Azazel/p/14985466.html
Copyright © 2011-2022 走看看