【bzoj4636】【蒟蒻的数列】【线段树】

Description

蒟蒻DCrusher不仅喜欢玩扑克,还喜欢研究数列
题目描述
DCrusher有一个数列,初始值均为0,他进行N次操作,每次将数列[a,b)这个区间中所有比k小的数改为k,他想知
道N次操作后数列中所有元素的和。他还要玩其他游戏,所以这个问题留给你解决。

Input

第一行一个整数N,然后有N行,每行三个正整数a、b、k。
N<=40000 , a、b、k<=10^9

Output

一个数,数列中所有元素的和

Sample Input

4
2 5 1
9 10 4
6 8 2
4 6 3

Sample Output

16

题解: 直接在线段树上打标记,最后dfs一遍整棵线段树即可.

因为区间长度比较大,所以需要动态开点.

注意一些没有建立的节点也是有贡献的,要把这些加进去.

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#define N 40010
#define inf 1000000000
using namespace std;
int n,a,b,k,cnt,root,ls[N*40],rs[N*40],v[N*40];
long long ans;
int read(){
  int x(0);char ch=getchar();
  while (ch<'0'||ch>'9') ch=getchar();
  while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
  return x;
}
void insert(int &k,int l,int r,int ll,int rr,int x){
  if (!k) k=++cnt;
  int mid=(l+r)>>1;
  if (l==ll&&r==rr){
    v[k]=max(v[k],x);
    //cout<<l<<' '<<r<<' '<<v[k]<<endl;
    return;
  }
  if (rr<=mid) insert(ls[k],l,mid,ll,rr,x);
  else if (mid<ll) insert(rs[k],mid+1,r,ll,rr,x);
  else{
    insert(ls[k],l,mid,ll,mid,x);
    insert(rs[k],mid+1,r,mid+1,rr,x);
  }
}
void query(int k,int l,int r,int x){
  int mid=(l+r)>>1;
  if (!k) return;
  v[k]=max(v[k],x);
  if (!ls[k]&&!rs[k]){
    //cout<<l<<' '<<r<<' '<<v[k]<<endl;
    ans+=(long long)(r-l+1)*v[k];
    return;
  }
  query(ls[k],l,mid,v[k]);
  query(rs[k],mid+1,r,v[k]);
  if (!ls[k]) ans+=(long long)(mid-l+1)*v[k];
  if (!rs[k]) ans+=(long long)(r-mid)*v[k]; 
}
int main(){
  //freopen("a.in","r",stdin);
  n=read(); 
  for (int i=1;i<=n;i++){
    a=read();b=read();k=read();
    if (a==b) continue;
    insert(root,1,inf,a,b-1,k);
  }
  query(root,1,inf,0);
  cout<<ans<<endl;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值