codevs4927 线段树练习5

题目描述 Description

有n个数和5种操作

add a b c:把区间[a,b]内的所有数都增加c

set a b c:把区间[a,b]内的所有数都设为c

sum a b:查询区间[a,b]的区间和

max a b:查询区间[a,b]的最大值

min a b:查询区间[a,b]的最小值

输入描述 Input Description

第一行两个整数n,m,第二行n个整数表示这n个数的初始值

接下来m行操作,同题目描述

输出描述 Output Description

对于所有的sum、max、min询问,一行输出一个答案

样例输入 Sample Input

10 6

3 9 2 8 1 7 5 0 4 6

add 4 9 4

set 2 6 2

add 3 8 2

sum 2 10

max 1 7

min 3 6

样例输出 Sample Output

49

11

4

数据范围及提示 Data Size & Hint

10%:1<n,m<=10

30%:1<n,m<=10000

100%:1<n,m<=100000

保证中间结果在long long(C/C++)、int64(pascal)范围内

 


正解:线段树

解题报告:

  这就是传说中的线段树综合题,所有标记都有。

  注意一点,就是我的执行顺序是先add标记下传,然后才是set标记下传,但下传过程中set可以覆盖add。开始我一直WA,后来才发现了一个错误,就是我先执行的add,那么,如果当前结点上此时既有set又有add,那么只能说明add一定是在set之后执行的,不然执行set的时候add早已经下传,所以我可以考虑直接把add的值直接加在set上去,就可以避免有一部分add没有发挥作用。害得我调试了半个小时。

 

  1 //It is made by jump~
  2 #include <iostream>
  3 #include <cstdlib>
  4 #include <cstring>
  5 #include <cstdio>
  6 #include <cmath>
  7 #include <algorithm>
  8 #include <ctime>
  9 #include <vector>
 10 #include <queue>
 11 #include <map>
 12 #include <set>
 13 using namespace std;
 14 typedef long long LL;
 15 #define RG register
 16 const int MAXN = 100011;
 17 int n,m,ql,qr;
 18 LL val,ans,inf;
 19 char ch[10];
 20 struct node{
 21     int l,r;
 22     LL minl,maxl,sum,add,set;
 23     bool flag;
 24 }a[MAXN*3];
 25 
 26 inline LL getint(){RG LL w=0,q=0; char c=getchar();while((c<'0' || c>'9') && c!='-') c=getchar(); if(c=='-') q=1,c=getchar();while (c>='0' && c<='9') w=w*10+c-'0', c=getchar(); return q ? -w : w;}
 27 
 28 inline void update(RG int root){
 29     RG int lc=root*2,rc=lc+1;  a[root].maxl=max(a[lc].maxl,a[rc].maxl);
 30     a[root].sum=a[lc].sum+a[rc].sum;  a[root].minl=min(a[lc].minl,a[rc].minl);
 31 }
 32 
 33 inline void build(RG int root,RG int l,RG int r){
 34     a[root].l=l; a[root].r=r;
 35     if(l==r) {    a[root].minl=a[root].maxl=a[root].sum=getint();    return ;  }
 36     RG int mid=(l+r)/2; RG int lc=root*2,rc=lc+1;
 37     build(lc,l,mid); build(rc,mid+1,r); update(root);
 38 }
 39 
 40 inline void pushdown(int root,int l,int r){
 41     if(!a[root].flag) return ; if(l==r) { a[root].flag=false; a[root].set=0; return ; }
 42     int lc=root*2,rc=lc+1; int mid=(l+r)/2;
 43     a[lc].set=a[rc].set=a[root].set; a[root].add=a[lc].add=a[rc].add=0;
 44     a[lc].maxl=a[rc].maxl=a[lc].minl=a[rc].minl=a[root].set;
 45     a[lc].sum=(LL)(mid-l+1)*a[root].set; a[rc].sum=(LL)(r-mid)*a[root].set;  a[root].sum=a[lc].sum+a[rc].sum;
 46     a[lc].flag=a[rc].flag=true;
 47     a[root].set=0; a[root].flag=false;
 48 }
 49 
 50 inline void pushdown_add(RG int root,RG int l,RG int r){
 51     if(l==r) { a[root].add=0; return ; } if(a[root].add==0) return ;
 52  
 53     if(a[root].flag){ a[root].set+=a[root].add; a[root].add=0; return ; }//至关重要,因为add打在set的后面,这就意味着相当于我们可以把set设的值变大一点
 54 
 55     RG int mid=(l+r)/2; RG int lc=root*2,rc=lc+1; a[lc].add+=a[root].add; a[rc].add+=a[root].add;    
 56     a[lc].minl+=a[root].add; a[lc].maxl+=a[root].add; a[rc].minl+=a[root].add; a[rc].maxl+=a[root].add;
 57     a[lc].sum+=a[root].add*(LL)(mid-l+1); a[rc].sum+=a[root].add*(LL)(r-mid);
 58     a[root].add=0; a[root].sum=a[lc].sum+a[rc].sum;
 59 }
 60 
 61 inline void add(RG int root,RG int l,RG int r){
 62     pushdown_add(root,l,r); pushdown(root,l,r); 
 63     if(ql<=l && r<=qr) { a[root].add+=val; a[root].maxl+=val; a[root].minl+=val; a[root].sum+=val*(LL)(r-l+1); return ; }
 64     RG int mid=(l+r)/2; RG int lc=root*2,rc=lc+1; if(ql<=mid) add(lc,l,mid); if(qr>mid) add(rc,mid+1,r);
 65     update(root);
 66 }
 67 
 68 inline void update_set(RG int root,RG int l,RG int r){    
 69     if(ql<=l && r<=qr) { a[root].flag=true; a[root].minl=a[root].maxl=a[root].set=val; a[root].add=0; a[root].sum=(LL)(r-l+1)*val; return ; } 
 70     pushdown_add(root,l,r); pushdown(root,l,r);
 71     RG int mid=(l+r)/2;RG int lc=root*2,rc=lc+1;
 72     if(ql<=mid) update_set(lc,l,mid); if(qr>mid) update_set(rc,mid+1,r); update(root);
 73 }
 74 
 75 inline void query_sum(RG int root,RG int l,RG int r){
 76     pushdown_add(root,l,r);  pushdown(root,l,r);
 77     if(ql<=l && r<=qr){ ans+=a[root].sum; return ; }
 78     RG int mid=(l+r)/2; RG int lc=root*2,rc=lc+1; 
 79     if(ql<=mid) query_sum(lc,l,mid); if(qr>mid) query_sum(rc,mid+1,r); update(root);
 80 }
 81 
 82 inline void query_max(RG int root,RG int l,RG int r){
 83     pushdown_add(root,l,r); pushdown(root,l,r);
 84     if(ql<=l && r<=qr){ ans=max(a[root].maxl,ans); return ; }
 85     RG int mid=(l+r)/2; RG int lc=root*2,rc=lc+1; 
 86     if(ql<=mid) query_max(lc,l,mid); if(qr>mid) query_max(rc,mid+1,r); update(root);
 87 }
 88 
 89 inline void query_min(RG int root,RG int l,RG int r){
 90     pushdown_add(root,l,r); pushdown(root,l,r);
 91     if(ql<=l && r<=qr){ ans=min(a[root].minl,ans); return ; }
 92     RG int mid=(l+r)/2; RG int lc=root*2,rc=lc+1; 
 93     if(ql<=mid) query_min(lc,l,mid); if(qr>mid) query_min(rc,mid+1,r); update(root);
 94 }
 95 
 96 inline void work(){
 97     n=getint(); m=getint(); build(1,1,n); inf=1; for(RG int i=1;i<=62;i++) inf*=2;
 98     while(m--) {
 99     scanf("%s",ch);
100     if(ch[0]=='a') { ql=getint(); qr=getint(); val=getint(); add(1,1,n); }
101     else if(ch[0]=='s' && ch[1]=='e') { ql=getint(); qr=getint(); val=getint(); update_set(1,1,n); }
102     else if(ch[0]=='s' && ch[1]=='u') { ql=getint(); qr=getint(); ans=0; query_sum(1,1,n); printf("%lld\n",ans); }
103     else if(ch[0]=='m' && ch[1]=='a') { ql=getint(); qr=getint(); ans=-inf; query_max(1,1,n); printf("%lld\n",ans); }
104     else{ ql=getint(); qr=getint(); ans=inf; query_min(1,1,n); printf("%lld\n",ans); }
105     }
106 }
107 
108 int main()
109 {
110   work();
111   return 0;
112 }

 

转载于:https://www.cnblogs.com/ljh2000-jump/p/5879470.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在信号处理领域,DOA(Direction of Arrival)估计是一项关键技术,主要用于确定多个信号源到达接收阵列的方向。本文将详细探讨三种ESPRIT(Estimation of Signal Parameters via Rotational Invariance Techniques)算法在DOA估计中的实现,以及它们在MATLAB环境中的具体应用。 ESPRIT算法是由Paul Kailath等人于1986年提出的,其核心思想是利用阵列数据的旋转不变性来估计信号源的角度。这种算法相比传统的 MUSIC(Multiple Signal Classification)算法具有较低的计算复杂度,且无需进行特征值分解,因此在实际应用中颇具优势。 1. 普通ESPRIT算法 普通ESPRIT算法分为两个主要步骤:构造等效旋转不变系统和估计角度。通过空间平移(如延时)构建两个子阵列,使得它们之间的关系具有旋转不变性。然后,通过对子阵列数据进行最小二乘拟合,可以得到信号源的角频率估计,进一步转换为DOA估计。 2. 常规ESPRIT算法实现 在描述中提到的`common_esprit_method1.m`和`common_esprit_method2.m`是两种不同的普通ESPRIT算法实现。它们可能在实现细节上略有差异,比如选择子阵列的方式、参数估计的策略等。MATLAB代码通常会包含预处理步骤(如数据归一化)、子阵列构造、旋转不变性矩阵的建立、最小二乘估计等部分。通过运行这两个文件,可以比较它们在估计精度和计算效率上的异同。 3. TLS_ESPRIT算法 TLS(Total Least Squares)ESPRIT是对普通ESPRIT的优化,它考虑了数据噪声的影响,提高了估计的稳健性。在TLS_ESPRIT算法中,不假设数据噪声是高斯白噪声,而是采用总最小二乘准则来拟合数据。这使得算法在噪声环境下表现更优。`TLS_esprit.m`文件应该包含了TLS_ESPRIT算法的完整实现,包括TLS估计的步骤和旋转不变性矩阵的改进处理。 在实际应用中,选择合适的ESPRIT变体取决于系统条件,例如噪声水平、信号质量以及计算资源。通过MATLAB实现,研究者和工程师可以方便地比较不同算法的效果,并根据需要进行调整和优化。同时,这些代码也为教学和学习DOA估计提供了一个直观的平台,有助于深入理解ESPRIT算法的工作原理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值