zoukankan      html  css  js  c++  java
  • Codeforces 961E Tufurama

    题目链接

    https://codeforces.com/contest/961/problem/E 

    题意:

      给你一个长度为 N 的数组 A

      问 j < i && a[i] >= j  && a[j] >= i 的 (i , j) 有多少对

    分析:

      权值线段树

      其实这是道主席树裸题 , 但我想介绍一种权值线段树的做法

      根据条件我们可以把问题转换成 [1 , min(a[i] , i - 1)] 内有多少个 j 使得 a[j] >= i

      即给你一个数组 A , 以及 N 个询问Q , 每次问你 [L , R] 内大于等于 X 的数有多少个

      我个人习惯求 [L , R] 内小于 X 的数有多少个

      那么这样每个询问对答案的贡献就是 R - L + 1 - cnt

      首先我们可以将询问储存下来:

      对于第 i 个询问 , 它的 L = 1 , R = min(a[i] , i  - 1) , X = i

      然后对所有询问按照 X 的大小升序排序 

      对于数组 A , 我们记录每个数下标的位置后 , 也按照ai的大小升序排序

      接下来我们就可以开始枚举询问了

      对于第 i 个询问 , 我们把数组A中小于Q[i].X的数的下标对应权值线段树的位置 + 1

      表示原数组中这一个位置有 1 个数是小于 Q[i].X的

      待所有A中小于 Q[i].X的数加入到权值线段树中  , 我们再查询 [L , R] 的区间和

      此时查询的结果 = 小于Q[i].X的数的个数,因为我们只把小于Q[i].X的数插入了权值线段树中

      所以查询的结果就是区间内小于 Q[i].X 的数的个数(算是一种小套路吧)

    #include<bits/stdc++.h>
    #define ios std::ios::sync_with_stdio(false)
    #define rep(i,a,n) for (int i=a;i<=n;i++)
    #define per(i,n,a) for (int i=n;i>=a;i--)
    #define ll long long
    #define int long long
    #define il inline
    using namespace std;
    struct Tree
    {
        ll l,r,sum,lazy,maxn,minn;
    } tree[1000000];
    il void push_up(ll rt)
    {
        tree[rt].sum=tree[rt<<1].sum+tree[rt<<1|1].sum;
        tree[rt].maxn=max(tree[rt<<1].maxn,tree[rt<<1|1].maxn);
        tree[rt].minn=min(tree[rt<<1].minn,tree[rt<<1|1].minn);
    }
    il void push_down(ll rt , ll length)
    {
        if(tree[rt].lazy)
        {
            tree[rt<<1].lazy+=tree[rt].lazy;
            tree[rt<<1|1].lazy+=tree[rt].lazy;
            tree[rt<<1].sum+=(length-(length>>1))*tree[rt].lazy;
            tree[rt<<1|1].sum+=(length>>1)*tree[rt].lazy;
            tree[rt<<1].minn+=tree[rt].lazy;
            tree[rt<<1|1].minn+=tree[rt].lazy;
            tree[rt<<1].maxn+=tree[rt].lazy;
            tree[rt<<1|1].maxn+=tree[rt].lazy;
            tree[rt].lazy=0;
        }
    }
    il void build(ll l , ll r , ll rt , ll *aa)
    {
        tree[rt].lazy=0;
        tree[rt].l=l;
        tree[rt].r=r;
        if(l==r)
        {
            tree[rt].sum=aa[l];
            tree[rt].minn=tree[rt].sum;
            tree[rt].maxn=tree[rt].sum;
            return;
        }
        ll mid=(l+r)>>1;
        build(l,mid,rt<<1,aa);
        build(mid+1,r,rt<<1|1,aa);
        push_up(rt);
    }
    il void update_range(ll L , ll R , ll key , ll rt)
    {
        if(tree[rt].r<L||tree[rt].l>R)return;
        if(L<=tree[rt].l&&R>=tree[rt].r)
        {
            tree[rt].sum+=(tree[rt].r-tree[rt].l+1)*key;
            tree[rt].minn+=key;
            tree[rt].maxn+=key;
            tree[rt].lazy+=key;
            return;
        }
        push_down(rt,tree[rt].r-tree[rt].l+1);
        ll mid=(tree[rt].r+tree[rt].l)>>1;
        if(L<=mid)update_range(L,R,key,rt << 1);
        if(R>mid)update_range(L,R,key,rt << 1 | 1);
        push_up(rt);
    }
    il ll query_range(ll L, ll R, ll rt)
    {
        if(L<=tree[rt].l&&R>=tree[rt].r)
        {
            return tree[rt].sum;
        }
        push_down(rt,tree[rt].r-tree[rt].l+1);
        ll mid=(tree[rt].r+tree[rt].l)>>1;
        ll ans=0;
        if(L<=mid)ans+=query_range(L,R,rt << 1);
        if(R>mid)ans+=query_range(L,R,rt << 1 | 1);
        return ans;
    }
    
    const int N = 2e5 + 10;
    int n , k , ans;
    ll aa[N];
    struct node
    {
        int x , id;
        int l , r;
        bool operator < (const node &a) const
        {
            return x < a.x;
        }
    } a[N] , q[N];
    bool cmp(node a , node b){
        return a.id < b.id;
    }
    signed main()
    {
        ios;
        cin.tie(0);
        int n;
        cin >> n;
        rep(i , 1 , n)
        {
            cin >> a[i].x , a[i].id = i;
            q[i].x = q[i].id = i;
            q[i].l = 1 , q[i].r = min(a[i].x , i - 1);
        }
        sort(a + 1 , a + 1 + n);
        sort(q + 1 , q + 1 + n);
        int now = 1;
        build(1 , n , 1 , aa);
        rep(i , 1 , n)
        {
            int l = q[i].l , r = q[i].r , x = q[i].x;
            while(a[now].x < x && now <= n)
            {
                update_range(a[now].id , a[now].id , 1 , 1);
                now ++ ;
            }
            ans += r - l + 1 - query_range(l , r , 1);
        }
        cout << ans << '
    ';
        return 0;
    }

      

    凡所不能将我击倒的,都将使我更加强大
  • 相关阅读:
    Java 得到指定时间加半个小时之后得时间
    MySQL查询point类型类型的坐标,返回经度纬度
    MySQL通过实体经纬度字段插入数据库point类型的经纬度字段
    MySQL通过POIN数据类型查询指定范围内数据
    Java 根据两个经纬度,得到两点距离
    mysql通过经纬度查询400公里范围内的小区
    位运算
    Hibernate多对多删除问题的解决
    mysql 中 时间和日期函数
    Struts2数据传输的背后机制:ValueStack(值栈)
  • 原文地址:https://www.cnblogs.com/StarRoadTang/p/12655526.html
Copyright © 2011-2022 走看看