zoukankan      html  css  js  c++  java
  • bzoj4826:[Hnoi2017]影魔

    传送门

    首先知道每段([i,i+1])都能提供p1的贡献,预先加上就行了
    然后的区间都是3个以上的了
    对于p1的贡献,可以考虑中间的数(i),设(l[i])为左边第一个大于它的数的位置,(r[i])为右边第一个大于它的数的位置,对于每一个(l[i])(r[i])可以发现贡献是p1
    对于p2的贡献,可以沿用上面的定义,那么左端点在区间([l[i]+1,i-1])内,右端点为(r[i])的贡献为p2,左端点为(l[i]),右端点在区间([i+1,r[i]-1])内的贡献也为p2
    然后可以离线做,排个序,扫一遍
    假设当前询问区间为([l,r]),当枚举到(l-1)时统计一下([l,r])内所有贡献的和,到(r)时加上当时([l,r])内的贡献的和再减掉这个值
    写颗区间修改,区间查询的线段树就行了
    细节有点多!
    代码:

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    void read(int &x) {
    	char ch; bool ok;
    	for(ok=0,ch=getchar(); !isdigit(ch); ch=getchar()) if(ch=='-') ok=1;
    	for(x=0; isdigit(ch); x=x*10+ch-'0',ch=getchar()); if(ok) x=-x;
    }
    #define rg register
    const int maxn=2e5+10;
    int st[maxn],top,n,m,tot,p1,p2,a[maxn];long long ans[maxn];
    struct oo{int x,y,i;}l[maxn],r[maxn];
    struct o{int x,id,y,type;}f[maxn*2];
    struct segment_tree{int l,r,lazy;long long sum;}s[maxn*4];
    bool cmp(o a,o b){return a.x<b.x;}
    bool Cmp(oo a,oo b){return a.x<b.x;}
    void update(int x){s[x].sum=s[x<<1].sum+s[x<<1|1].sum;}
    void build(int x,int l,int r)
    {
    	s[x].l=l,s[x].r=r;int mid=(l+r)>>1;
    	if(l==r)return ;
    	build(x<<1,l,mid),build(x<<1|1,mid+1,r);
    }
    void pushdown(int x)
    {
    	s[x<<1].lazy+=s[x].lazy,s[x<<1|1].lazy+=s[x].lazy;
    	s[x<<1].sum+=1ll*(s[x<<1].r-s[x<<1].l+1)*s[x].lazy;
    	s[x<<1|1].sum+=1ll*(s[x<<1|1].r-s[x<<1|1].l+1)*s[x].lazy;
    	s[x].lazy=0;
    }
    void change(int x,int l,int r,int v)
    {
    	if(l>r)return ;
    	if(l<=s[x].l&&r>=s[x].r)
    	{
    		s[x].sum+=1ll*(s[x].r-s[x].l+1)*v,s[x].lazy+=v;
    		return ;
    	}
    	if(s[x].lazy)pushdown(x);
    	int mid=(s[x].l+s[x].r)>>1;
    	if(l<=mid)change(x<<1,l,r,v);
    	if(r>mid)change(x<<1|1,l,r,v);
    	update(x);
    }
    long long get(int x,int l,int r)
    {
    	if(l>r)return 0;
    	if(l<=s[x].l&&r>=s[x].r)return s[x].sum;
    	if(s[x].lazy)pushdown(x);
    	int mid=(s[x].l+s[x].r)>>1;long long ans=0;
    	if(l<=mid)ans+=get(x<<1,l,r);
    	if(r>mid)ans+=get(x<<1|1,l,r);
    	return ans;
    }
    int main()
    {
    	read(n),read(m),read(p1),read(p2);
    	for(rg int i=1;i<=n;i++)read(a[i]);
    	for(rg int i=1;i<=n;i++)
    	{
    		while(top&&a[st[top]]<a[i])top--;
    		l[i].x=st[top],l[i].i=i,st[++top]=i;
    	}
    	top=0;
    	for(rg int i=n;i;i--)
    	{
    		while(top&&a[st[top]]<a[i])top--;
    		r[i].x=st[top],r[i].i=i,st[++top]=i;
    	}
    	for(rg int i=1;i<=n;i++)r[i].x=r[i].x?r[i].x:n+1,l[i].y=r[i].x,r[i].y=l[i].x;
    	for(rg int i=1,x,y;i<=m;i++)
    		read(x),read(y),ans[i]+=1ll*(y-x)*p1,
    		f[++tot].type=0,f[tot].id=i,f[tot].x=x-1,f[tot].y=y,
    		f[++tot].type=1,f[tot].id=i,f[tot].x=y,f[tot].y=x;
    	sort(f+1,f+tot+1,cmp),sort(l+1,l+n+1,Cmp),sort(r+1,r+n+1,Cmp);
    	int now1=1,now2=1,now3=1;build(1,1,n);
    	while(!f[now3].x)now3++;
    	for(rg int i=1;i<=n;i++)
    	{
    		while(now1<=n&&l[now1].x<=i)
    		{
    			if(1<=l[now1].x)change(1,l[now1].i+1,l[now1].y-1,p2);
    			now1++;
    		}
    		while(now2<=n&&r[now2].x<=i)
    		{
    			change(1,r[now2].y+1,r[now2].i-1,p2);
    			if(r[now2].y)change(1,r[now2].y,r[now2].y,p1);
    			now2++;
    		}
    		while(now3<=tot&&f[now3].x<=i)
    		{
    			if(!f[now3].type)ans[f[now3].id]-=get(1,f[now3].x+1,f[now3].y);
    			else ans[f[now3].id]+=get(1,f[now3].y,f[now3].x);
    			now3++;
    		}
    	}
    	for(rg int i=1;i<=m;i++)printf("%lld
    ",ans[i]);
    }
    
  • 相关阅读:
    win10 uwp 弹起键盘不隐藏界面元素
    win10 uwp 存放网络图片到本地
    win10 uwp 存放网络图片到本地
    sublime Text 正则替换
    sublime Text 正则替换
    win10 uwp 绘图 Line 控件使用
    win10 uwp 绘图 Line 控件使用
    AJAX 是什么?
    什么是 PHP SimpleXML?
    PHP XML DOM:DOM 是什么?
  • 原文地址:https://www.cnblogs.com/lcxer/p/10485821.html
Copyright © 2011-2022 走看看