zoukankan      html  css  js  c++  java
  • P5012-水の数列【并查集,RMQ】

    正题

    题目链接:https://www.luogu.com.cn/problem/P5012


    题目大意

    (n)个数字的一个序列,(T)次询问给出([l,r])要求

    • 找出一个最大的(x)满足。提出所有的小于(x)的数,然后被提出的数的连续区间长度平方和除以(x)的值最大
    • 要求分出来的区间个数在([l,r])之间
    • 强制在线

    (1leq nleq 10^6,1leq Tleq 10^3,1leq a_ileq 10^6)


    解题思路

    考虑到(x)的取值不会超过([1,10^6]),所以暴力枚举(x),然后用并查集合并区间计算出每个(x)的区间个数和长度平方和。

    然后丢到对应位置跑(RMQ)就好了。

    时间复杂度(O(nlog n+Q))


    code

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    #define ll long long 
    using namespace std;
    const ll N=1e6+10;
    ll n,T,lg[N/2],fa[N],siz[N],w[N];
    ll ans,L,f[N/2][20],co[N];
    vector<ll> v[N];bool k[N];
    ll find(ll x)
    {return (fa[x]==x)?x:(fa[x]=find(fa[x]));}
    void Merge(ll x,ll y){
    	x=find(x);y=find(y);
    	ans-=siz[x]*siz[x]+siz[y]*siz[y];
    	fa[y]=x;siz[x]+=siz[y];
    	ans+=siz[x]*siz[x];
    	return;
    }
    ll Ask(ll l,ll r){
    	if(l>L)return 0;
    	if(r>L)r=L;
    	ll z=lg[r-l+1];
    	ll x=f[l][z],y=f[r-(1<<z)+1][z];
    	if(w[x]*co[y]>w[y]*co[x])return x;
    	return y;
    }
    signed main()
    {
    	scanf("%lld%lld",&n,&T);
    	for(ll i=1;i<=n;i++){
    		ll x;scanf("%lld",&x);
    		v[x].push_back(i);
    		fa[i]=i;siz[i]=co[i]=1;
    	}
    	ll cnt=0;
    	for(ll i=1;i<=1e6;i++){
    		for(ll j=0;j<v[i].size();j++){
    			ll x=v[i][j];k[x]=1;ans++;cnt++;
    			if(k[x-1])Merge(x-1,x),cnt--;
    			if(k[x+1])Merge(x,x+1),cnt--;
    		}
    		if(w[cnt]*i<=ans*co[cnt])w[cnt]=ans,co[cnt]=i;
    		L=max(L,cnt);
    	}
    	for(ll i=1;i<=L;i++)f[i][0]=i;
    	for(ll i=2;i<=L;i++)lg[i]=lg[i>>1]+1;
    	for(ll j=1;(1<<j)<=L;j++)
    		for(ll i=1;i+(1<<j)-1<=L;i++){
    			ll x=f[i][j-1],y=f[i+(1<<j-1)][j-1];
    			if(w[x]*co[y]>w[y]*co[x])f[i][j]=x;
    			else f[i][j]=y;
    		}
    	ans=0;
    	while(T--){
    		ll a,b,x,y;
    		scanf("%lld%lld%lld%lld",&a,&b,&x,&y);
    		ll l=(a*ans+x-1)%n+1;
    		ll r=(b*ans+y-1)%n+1;
    		if(l>r)swap(l,r);
    		ll p=Ask(l,r);
    		if(!w[p])printf("-1 -1
    ");
    		else printf("%lld %lld
    ",w[p],co[p]);
    		printf("%lld %lld %lld
    ",l,r,ans);
    		ans=w[p]?(w[p]*co[p]%n):1;
    	}
    	return 0;
    }
    
  • 相关阅读:
    怎么在java 8的map中使用stream
    在java 8 stream表达式中实现if/else逻辑
    Lambda表达式最佳实践
    java并发Exchanger的使用
    java中functional interface的分类和使用
    java 8 Streams简介
    一篇文章让你彻底弄懂SSL/TLS协议
    基于口令的密码(PBE)
    更加安全的密钥生成方法Diffie-Hellman
    有关密钥的最全总结都在这了
  • 原文地址:https://www.cnblogs.com/QuantAsk/p/14630841.html
Copyright © 2011-2022 走看看