• P4755 Beautiful Pair(可持久化线段树+单调栈+启发式合并的思想)


    小D有一个数列a。

    当一个数对(i,j)满足a[i]*a[j]<=max[a[i],a[i+1],...a[j]]的时候

    才被统计。

    询问有多少对数对。

    做法:

    先单调栈处理出每个数作为最大值的区间,为了避免重复计算,这里对左边找第一个>=a[i]的数,对右边找第一个>a[i]的数,这样就可以去重。

    然后对每个数,根据这个数的位置可以划分为左区间和右区间,对于这个东西可以每次枚举较小的那个区间,这样启发式的枚举,时间复杂度是O(nlognlogn)的

    //对每个数处理出它作为最大值的左右区间
    //然后枚举较短的那个区间计算较长的那个区间
    //均摊时间复杂度O(nlogn)
    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1e5+10;
    const int M=maxn*40;
    int n,a[maxn],L[maxn],R[maxn];
    int T[maxn],c[M],lson[M],rson[M],tot;
    
    int build (int l,int r) {
    	int u=++tot;
    	if (l==r) {
    		c[u]=0;
    		return u;
    	}
    	int mid=(l+r)>>1;
    	lson[u]=build(l,mid);
    	rson[u]=build(mid+1,r);
    	c[u]=c[lson[u]]+c[rson[u]];
    	return u;
    } 
    int up (int u,int l,int r,int p,int v) {
    	int newRoot=++tot;
    	c[newRoot]=c[u]+v;
    	if (l==r) return newRoot;
    	int mid=(l+r)>>1;
    	lson[newRoot]=lson[u];
    	rson[newRoot]=rson[u];
    	if (p<=mid) lson[newRoot]=up(lson[u],l,mid,p,v);
    	if (p>mid) rson[newRoot]=up(rson[u],mid+1,r,p,v);
    	return newRoot; 
    }
    int query (int lr,int rr,int l,int r,int L,int R) {
    	if (L>R) return 0;
    	if (l>=L&&r<=R) return c[rr]-c[lr];
    	int mid=(l+r)>>1;
    	int ans=0;
    	if (L<=mid) ans+=query(lson[lr],lson[rr],l,mid,L,R);
    	if (R>mid) ans+=query(rson[lr],rson[rr],mid+1,r,L,R);
    	return ans;
    }
    int t[maxn],mm;
    int main () {
    	scanf("%d",&n);
    	for (int i=1;i<=n;i++) scanf("%d",a+i),t[i]=a[i],L[i]=1,R[i]=n;
    	sort(t+1,t+n+1);
    	mm=unique(t+1,t+n+1)-t-1;
    	for (int i=1;i<=n;i++) a[i]=upper_bound(t+1,t+mm+1,a[i])-t-1;
    	stack<int> st;
    	for (int i=1;i<=n;i++) {
    		while(st.size()) {
    			if (a[st.top()]>=a[i]) {
    				L[i]=st.top()+1;
    				break;
    			}
    			st.pop();
    		}
    		st.push(i);
    	}
    	while (st.size()) st.pop();
    	for (int i=n;i>=1;i--) {
    		while (st.size()) {
    			if (a[st.top()]>a[i]) {
    				R[i]=st.top()-1;
    				break;
    			}
    			st.pop();
    		}
    		st.push(i);
    	}
    	long long ans=0;
    	T[0]=build(1,mm);
    	//7 7 7 7 7
    	for (int i=1;i<=n;i++) T[i]=up(T[i-1],1,mm,a[i],1);
    	for (int i=1;i<=n;i++) {
    		int x=i-L[i]+1;
    		int y=R[i]-i+1;
    		if (x<=y) {
    			for (int j=L[i];j<=i;j++) {
    				int re=(t[a[i]]/t[a[j]]);
    				//printf("%d
    ",re);
    				int p=upper_bound(t+1,t+mm+1,re)-t-1;
    				ans+=query(T[i-1],T[R[i]],1,mm,1,p);
    			}
    		}
    		else {
    			for (int j=i;j<=R[i];j++) {
    				int re=(t[a[i]]/t[a[j]]);
    				//printf("%d
    ",re);
    				int p=upper_bound(t+1,t+mm+1,re)-t-1;
    				ans+=query(T[L[i]-1],T[i],1,mm,1,p);
    			}
    		}
    	}
    	printf("%lld
    ",ans);
    }
  • 相关阅读:
    python之生成器
    Python 类(一)
    Python OOP(面向对象编程)
    python 静态方法、类方法(二)
    记一个有想法没能力实现的产品形态——实时公交
    ubuntu12.04离线安装libjpeg62-dev
    linux内核container_of宏定义分析
    signal函数理解或者void (*signal(int signum,void(*handler)(int)))(int)理解
    HttpServlet cannot be resolved to a type解决方法
    ubuntu12.04不能记住上次编辑位置的解决方案
  • 原文地址:https://www.cnblogs.com/zhanglichen/p/15420968.html
Copyright © 2020-2023  润新知