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\n",ans);

        }
    }
}
View Code

猜你喜欢

转载自www.cnblogs.com/ctyakwf/p/12616499.html
今日推荐