Codeforces 961E 主席树

题意:

给出一个n个数的序列,求有几对(i,j)满足a[i]>=j&&a[j]>=i,(i,j)和(j,i)只能算一对。

 

考虑第i个数会有几个j(j<i)满足条件,首先a[i]>=j就是查询的区间就是[1,a[i]],a[j]>i也就是查询区间[1,a[i]]中有几个a[j]>=i。

岂不主席树?注意去重就行了。

//by zykykyk
#include<cstdio>
#include<ctime>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<string>
#define rg register
#define il inline
#define vd void
#define ll long long
#define N 200010
#define For(i,x,y) for (rg ll i=(x);i<=(y);i++)
#define Dow(i,x,y) for (rg int i=(x);i>=(y);i--)
#define cross(i,k) for (rg int i=first[k];i;i=last[i])
using namespace std;
il ll max(ll x,ll y){return x>y?x:y;}
il ll min(ll x,ll y){return x<y?x:y;}
il ll read(){
    ll x=0;int ch=getchar(),f=1;
    while (!isdigit(ch)&&(ch!='-')&&(ch!=EOF)) ch=getchar();
    if (ch=='-'){f=-1;ch=getchar();}
    while (isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    return x*f;
}
int n,tot,a[N];
ll ans;

int sum,rt[N],v[N*33],lson[N*33],rson[N*33];
il vd insert(int &u,int last,int l,int r,int k){
    u=++sum,v[u]=v[last]+1;
    if (l==r) return;
    lson[u]=lson[last],rson[u]=rson[last];int mid=l+r>>1;
    if (k<=mid) insert(lson[u],lson[u],l,mid,k);
        else insert(rson[u],rson[u],mid+1,r,k);
}
il ll query(int u,int l,int r,int ql,int qr){
    if (l>=ql&&r<=qr) return 1ll*v[u];
    int mid=l+r>>1;
    if (qr<=mid) return query(lson[u],l,mid,ql,qr);
    else if (ql>mid) return query(rson[u],mid+1,r,ql,qr);
    else return query(lson[u],l,mid,ql,qr)+query(rson[u],mid+1,r,ql,qr); 
}

int main(){
    n=read();
    For(i,1,n) a[i]=read();
    For(i,1,n) insert(rt[i],rt[i-1],1,1e9,a[i]);
    For(i,1,n)
        if (a[i]==i) ans+=query(rt[a[i]],1,1e9,i,1e9)-1;
        else if (a[i]<i) ans+=query(rt[a[i]],1,1e9,i,1e9);
        else ans+=query(rt[i],1,1e9,i,1e9)-1;
    printf("%lld",ans);
}

 

posted @ 2018-04-11 21:09  zykykyk  阅读(363)  评论(0编辑  收藏  举报