zoukankan      html  css  js  c++  java
  • Luogu3722 影魔

    真的比较神的一个题

    Description

    link

    给定一个排列,如果点对 ((i,j)) 满足:

    (1.) (i ightarrow j) 中(两端不含)元素均小于 (p_i)(p_j) 则产生 (a_1) 点贡献

    (2.) (i ightarrow j)中(两端不含)元素的最大值如果在(p_i)(p_j) 之间则产生 (a_2) 点贡献

    Solution

    首先发现要贡献法……想不到就没救啦

    分开考虑两种值

    第一种我们枚举一个点当做区间最大值,找到左右离得最近的比它大的两个数,这里就产生了贡献

    然后第二种

    对于每个点(i)

    (l ightarrow i)(r)

    (i ightarrow r)(l)

    分别是满足条件的

    然后我们看怎么求

    左右的两个大数是可以单调栈求的

    for(int i=1;i<=n+1;++i) 
    {
    	while(top&&a[st[top]]<a[i]) r[st[top]]=i,top--;
    	l[i]=st[top]; st[++top]=i;
    }
    

    然后我们统计答案(蒟蒻不会这里的统计答案)

    其实就是个区间加区间求和的线段树,不知道为啥没想到

    还搞了(std) 才看懂……

    Code

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    namespace yspm{
    	inline int read()
    	{
    		int res=0,f=1; char k;
    		while(!isdigit(k=getchar())) if(k=='-') f=-1;
    		while(isdigit(k)) res=res*10+k-'0',k=getchar();
    		return res*f;
    	}
    	const int N=2e5+10;
    	struct tree{
    		int l,r,sum,add;
    		#define l(p) t[p].l
    		#define r(p) t[p].r
    		#define sum(p) t[p].sum
    		#define add(p) t[p].add
    	}t[N<<5];
    	int rt[N],tot,l[N],r[N],st[N],top,n,m,p1,p2,a[N];
    	inline void build(int p,int l,int r)
    	{
    		l(p)=l; r(p)=r; if(l==r) return ;
    		int mid=(l+r)>>1; build(p<<1,l,mid); build(p<<1|1,mid+1,r);
    		return ;
    	}
    	inline void spread(int p)
    	{
    		if(add(p))
    		{
    			sum(p<<1)+=add(p)*(r(p<<1)-l(p<<1)+1);
    			sum(p<<1|1)+=add(p)*(r(p<<1|1)-l(p<<1|1)+1);
    			add(p<<1)+=add(p); add(p<<1|1)+=add(p);
    		}return add(p)=0,void();
    	}
    	inline void push_up(int p){return sum(p)=sum(p<<1)+sum(p<<1|1),void();}
    	inline void update(int p,int l,int r,int v)
    	{
    		if(l<=l(p)&&r(p)<=r) return sum(p)+=v*(r(p)-l(p)+1),add(p)+=v,void();
    		int mid=(l(p)+r(p))>>1; spread(p);
    		if(l<=mid) update(p<<1,l,r,v);
    		if(r>mid) update(p<<1|1,l,r,v); 
    		return push_up(p);
    	}
    	inline int ask(int p,int l,int r)
    	{
    		if(l<=l(p)&&r(p)<=r) return sum(p);
    		spread(p); int ans=0,mid=(l(p)+r(p))>>1;
    		if(l<=mid) ans+=ask(p<<1,l,r); if(r>mid) ans+=ask(p<<1|1,l,r);
    		return ans;
    	}
    	int ans[N];
    	struct node{
    		int l,r,id,val;
    	}; vector<node> vec1[N],vec2[N];
    	signed main()
    	{
    		n=read(); m=read(); p1=read(); p2=read();
    		for(int i=1;i<=n;++i) a[i]=read(); a[0]=a[n+1]=n+1;
    		for(int i=1;i<=n+1;++i) 
    		{
    			while(top&&a[st[top]]<a[i]) r[st[top]]=i,top--;
    			l[i]=st[top]; st[++top]=i;
    		}
    		for(int i=1;i<=m;++i) 
    		{
    			int tl=read(),tr=read();
    			ans[i]+=(tr-tl)*p1;
    			vec2[tl-1].push_back((node){tl,tr,i,0});
    			vec2[tr].push_back((node){tl,tr,i,0});
    		}
    		for(int i=1;i<=n;++i)
    		{
    			if(l[i]&&r[i]<=n) vec1[r[i]].push_back((node){l[i],l[i],0,p1});
    			if(l[i]&&r[i]>i+1) vec1[l[i]].push_back((node){i+1,r[i]-1,0,p2});
    			if(l[i]+1<i&&r[i]<=n) vec1[r[i]].push_back((node){l[i]+1,i-1,0,p2});
    		}
    		
    		build(1,1,n);
    		for(int i=1;i<=n;++i)
    		{
    			int siz=vec1[i].size();
    			for(int j=0;j<siz;++j) 
    			{
    				update(1,vec1[i][j].l,vec1[i][j].r,vec1[i][j].val);
    			}
    			siz=vec2[i].size();
    			for(int j=0;j<siz;++j) 
    			{
    				int sum=ask(1,vec2[i][j].l,vec2[i][j].r);
    				if(i==vec2[i][j].r) ans[vec2[i][j].id]+=sum; 
    				else ans[vec2[i][j].id]-=sum; 
    			}
    		}
    		for(int i=1;i<=m;++i) printf("%lld
    ",ans[i]);
    		return 0;
    	}
    }
    signed main(){return yspm::main();}
    

    Review

    (1.) 贡献法好!

    (2.) 提升代码能力和学习如何统计答案……

  • 相关阅读:
    利用相关的Aware接口
    java 值传递和引用传递。
    权限控制框架Spring Security 和Shiro 的总结
    优秀代码养成
    Servlet 基础知识
    leetcode 501. Find Mode in Binary Search Tree
    leetcode 530. Minimum Absolute Difference in BST
    leetcode 543. Diameter of Binary Tree
    leetcode 551. Student Attendance Record I
    leetcode 563. Binary Tree Tilt
  • 原文地址:https://www.cnblogs.com/yspm/p/12724839.html
Copyright © 2011-2022 走看看