【2019徐州网络赛 I】query(二维偏序)

Given a permutation pp of length nn, you are asked to answer mm queries, each query can be represented as a pair (l ,r )(l,r), you need to find the number of pair(i ,j)(i,j) such that $l≤i<j≤r a n d   min ⁡ ( p i , p j ) = gcd ⁡ ( p i , p j ) and\ \min(p_i,p_j) = \gcd(p_i,p_j ) and min(pi,pj)=gcd(pi,pj)
Input
There is two integers n(1 \le n \le 10^5)), m(1 \le m \le 10^5)in the first line, denoting the length of p and the number of queries.

In the second line, there is a permutation of length n, denoting the given permutation pp. It is guaranteed that p is a permutation of length n.

For the next mm lines, each line contains two integer l_i and r_i(1 <= l_i <=r_i <=n)denoting each query.

Output
For each query, print a single line containing only one integer which denotes the number of pair(i,j).

样例输入
3 2
1 2 3
1 3
2 3
样例输出
2
0

二维偏序
代码:

#include<iostream>
#include<cstdio>
#include<queue>
#include<algorithm>
#include<cstring>
#define maxx 1000005
#define N 26
using namespace std;
typedef long long ll;
struct node
{
    int l,r;
    int id;
}q[100005];
int ans[100005];
bool cmp1(node x1,node x2)
{
    return x1.r<x2.r;
}
struct node2
{
    int l,r;
    node2(int l,int r):l(l),r(r){}
};
bool cmp2(node2 x1,node2 x2)
{
    return x1.r<x2.r;
}
int a[100005];
vector<node2> b;
int n,m;
int c[maxx];
int total;
inline void add(int x)
{
    for(;x<=n;x+=x&-x)c[x]++;
}
inline int ask(int x)
{
    int ans=0;
    for(;x;x-=x&-x)ans+=c[x];
    return ans;
}

int main()
{
    cin>>n>>m;
    int x;
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&x);
        a[x]=i;
    }
    for(int i=1;i<=n;i++)
        for(int j=i+i;j<=n;j+=i)
        {
            int l=a[i],r=a[j];
            if(l>r)swap(l,r);
            b.push_back(node2(l,r));
        }
    sort(b.begin(),b.end(),cmp2);
    total=b.size();
    //for(int i=0;i<total;i++)cout<<b[i].l<<" "<<b[i].r<<endl;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&q[i].l,&q[i].r);
        q[i].id=i;
    }
    sort(q+1,q+1+m,cmp1);
    int now=0;

    for(int i=1;i<=m;i++)
    {
        while(now<total&&b[now].r<=q[i].r)
        {
            add(b[now].l);now++;
        }
        ans[q[i].id]=ask(q[i].r)-ask(q[i].l-1);
        //cout<<ans[q[i].id]<<endl;
    }
    for(int i=1;i<=m;i++)printf("%d\n",ans[i]);
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值