CodeForces 961E Tufurama (静态主席树做法)

题目链接:http://codeforces.com/problemset/problem/961/E

题目大意

给定一个序列a,
问有多少个二元组(x,y)满足
a[x]>=y&&a[y]>=x,x小于y,
统计这样的二元组个数。

题目分析 

明显构建主席树其权值总空间大小是n,
那么我们按序扫描,对于当前值x,
我们需要统计1到x区间中不小于位置i的个数,
注意x要小于i,所以我们取min(x,i-1)保证计数不会重复,
对于其查询不小于x 的个数,对其rt[min(x,i-1)]线段树进行区间统计
即可,因为这颗线段树保存的是前缀和性质。
本人在做题时遇到个想不通的地方就是:一加build初始化就错在
第七个样例,不加就对了(虽然不加确实没影响。。。)但
按照套路应该是加上无妨的。。有大佬看出来了麻烦留言交流下哈T_T...

#include<bits/stdc++.h>
using namespace std;

#define debug puts("YES");
#define rep(x,y,z) for(int (x)=(y);(x)<(z);(x)++)
#define ll long long

#define lrt int l,int r,int rt
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define root l,r,rt
#define mst(a,b) memset((a),(b),sizeof(a))
#define pii pair<int,int>
#define fi first
#define se second
#define mk(x,y) make_pair(x,y)
const int mod=1e9+7;
const int maxn=2e5+10;
const int ub=1e6;
const int N=1e9;
ll powmod(ll x,ll y){ll t; for(t=1;y;y>>=1,x=x*x%mod) if(y&1) t=t*x%mod; return t;}
ll gcd(ll x,ll y){return y?gcd(y,x%y):x;}
/*
题目大意:
给定一个序列a,
问有多少个二元组(x,y)满足
a[x]>=y&&a[y]>=x,x小于y,
统计这样的二元组个数。

题目分析:
明显构建主席树其权值总空间大小是n,
那么我们按序扫描,对于当前值x,
我们需要统计1到x区间中不小于位置i的个数,
注意x要小于i,所以我们取min(x,i-1)保证计数不会重复,
对于其查询不小于x 的个数,对其rt[min(x,i-1)]线段树进行区间统计
即可,因为这颗线段树保存的是前缀和性质。
本人在做题时遇到个想不通的地方就是:一加build初始化就错在
第七个样例,不加就对了(虽然不加确实没影响。。。)但
按照套路应该是加上无妨的。。有大佬看出来了麻烦留言交流下哈T_T...
*/
int a[maxn],n;
ll ans=0;
int rt[maxn],ls[maxn*20],rs[maxn*20];
int sum[maxn*20];
int tot=0;
void build(int& o,int l,int r){
    o=++tot;
    sum[o]=0;
    if(l==r) return ;
    int mid=l+r>>1;
    build(ls[o],l,mid);
    build(rs[o],mid+1,r);
}
void update(int& o,int l,int r,int last,int p){
    o=++tot;
    sum[o]=sum[last]+1;
    ls[o]=ls[last],rs[o]=rs[last];
    if(l==r) return ;
    int mid=l+r>>1;
    if(p<=mid) update(ls[o],l,mid,ls[last],p);
    else update(rs[o],mid+1,r,rs[last],p);
}
ll Query(int o,int l,int r,int pl,int pr){
    if(pl<=l&&r<=pr) return sum[o];
    int mid=l+r>>1;
    ll ret=0;
    if(pl<=mid) ret+=Query(ls[o],l,mid,pl,pr);
    if(mid<pr) ret+=Query(rs[o],mid+1,r,pl,pr);
    return ret;
}
int main(){
    scanf("%d",&n);
    ///build(rt[0],1,n);不能build。。。。不知道为什么T_T
    rep(i,1,n+1){
        scanf("%d",&a[i]);
        a[i]=min(a[i],n);
        update(rt[i],1,n,rt[i-1],a[i]);
        int tp=min(a[i],i-1);
        ans+=Query(rt[tp],1,n,i,n);
    }
    printf("%lld\n",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_37451344/article/details/88613233