• HDU6521 Party (线段树思维)


    1.首先明确这道题想要求取的是在l-r中新认识的人的对数

    如果想要知道新认识的人是多少,那么我们可能会考虑到上次认识的人的左右边界。并且可以想象到的是,在一个区间中,右边的人新认识的左边的人,其实就是左边的人新认识的右边的人

    如果重复的计算,那么最后要/2。所以我们可以直接考虑有边界

    2.有一个性质可以通过观察得到,也就是越往右的人的右边界一定大于等于左边的右边界,因为每次都是连续的一段区间,左边的人不可能绕过右边的人去认识更右边的人。所以这个维护的值是递增的

    那么每次新认识的人其实就是找到最右边的一个有边界小于r的点pos,答案就是(r-l+1)*r-从l-pos的r相加,也就是前面一段中每个离右边界的人数之和

    这样就发现了一个区间求和操作,之后我们要更改掉现有的有边界,也就是将l-pos这段的有边界都设置为r,这里有个区间修改操作。同时还需要一个函数来计算pos的位置

    这样就能看出线段树非常擅长这些

    对于区间问题,需要仔细想可以接受复杂度内的一些性质。以后还要多多锻炼,这个是向网上博客大佬学习后才发现的做法。

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<map>
    #include<algorithm>
    #include<queue>
    #define ull unsigned long long
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> pll;
    const int N=5e5+10;
    struct node{
        int l,r;
        ll sign;
        ll lazy;
        ll sum;
    }tr[N<<2];
    void pushup(int u){
        tr[u].sum=tr[u<<1].sum+tr[u<<1|1].sum;//边界的r和
        tr[u].sign=tr[u<<1|1].sign;//最右边界的更新,肯定是由右边更新而来
    }
    void build(int u,int l,int r){
        if(l==r){
            tr[u]=node{l,r,l,0,l};
        }
        else{
            int mid=l+r>>1;
            tr[u]={l,r};
            build(u<<1,l,mid);
            build(u<<1|1,mid+1,r);
            pushup(u);
        }
    }
    void pushdown(int u){
        tr[u<<1].lazy=tr[u<<1|1].lazy=tr[u].lazy;
        tr[u<<1].sign=tr[u<<1|1].sign=tr[u].lazy;
        tr[u<<1].sum=(tr[u<<1].r-tr[u<<1].l+1)*tr[u].lazy;
        tr[u<<1|1].sum=(tr[u<<1|1].r-tr[u<<1|1].l+1)*tr[u].lazy;
        tr[u].lazy=0;
    }
    void modify(int u,int l,int r,ll x){
        if(tr[u].l>=l&&tr[u].r<=r){
            tr[u].sign=x;
            tr[u].lazy=x;
            tr[u].sum=(tr[u].r-tr[u].l+1)*x;//对于范围内直接修改
            return ;
        }
        if(tr[u].lazy!=0)
            pushdown(u);
        int mid=tr[u].r+tr[u].l>>1;
        if(l<=mid)
            modify(u<<1,l,r,x);
        if(r>mid)
            modify(u<<1|1,l,r,x);
        pushup(u);
    }
    int querypos(int u,int x){
        if(tr[u].l==tr[u].r){
            if(tr[u].sign<=x)
                return tr[u].l;
            else
                return -1;//可能就没有满足条件的
        }
        if(tr[u].lazy)
        pushdown(u);
        if(tr[u<<1].sign<=x) //当左边满足条件,就要对两边的取max
            return max((int)tr[u<<1].r,querypos(u<<1|1,x));
        else{
            return querypos(u<<1,x);//不然就在左边
        }
    }
    ll query(int u,int l,int r){
        if(tr[u].l>=l&&tr[u].r<=r)
            return tr[u].sum;
        int mid=tr[u].l+tr[u].r>>1;
        if(tr[u].lazy)
        pushdown(u);
        ll ans=0;
        if(l<=mid)
            ans=query(u<<1,l,r);
        if(r>mid)
            ans+=query(u<<1|1,l,r);
        return ans;
    }
    int main(){
        int n,m;
        while(cin>>n>>m){
            build(1,1,n);
            while(m--){
                int l,r;
                scanf("%d%d",&l,&r);
                ll ans=0;
                int pos=querypos(1,r);
                if(pos<l)
                    ans=0;
                else{
                     ans=(ll)(pos-l+1)*r-query(1,l,pos);
                     modify(1,l,pos,r);
                }
                printf("%lld
    ",ans);
    
            }
        }
    }
    View Code
  • 相关阅读:
    fedora中使用 mariadb数据库建库和建表-- mariadb数据库服务无法启动?
    我在linux中使用的vundle 和 vimrc配置
    vim的加密和解密?
    gvim写html代码时如何快速地跳转到一个标签的结束位置: 终极插件: matchit.vim
    HTML5+CSS3整体回顾
    HTML5无刷新修改URL
    使用ab对nginx进行压力测试
    nginx php-fpm 输出php错误日志
    如何正确配置Nginx+PHP
    关于Nginx的一些优化(突破十万并发)
  • 原文地址:https://www.cnblogs.com/ctyakwf/p/12616499.html
Copyright © 2020-2023  润新知