天天看點

(線段樹)過滑動視窗

**上一次我們談論單調隊列,這樣是可以過滑動視窗的 
void slove_min()
{
   int head=1,tail=0;
   for(int i=1;i<=n;i++)
   {
   while(head<=tail&&q[head]+k<=i)
   head++;//更新掉太老的元素
   while(head<=tail&&a[q[tail]]>a[i])//更新掉頭元素,讓頭元素最小
   tail--;
   q[++tail]=i;//頭元素最小
   if(k<=i)
   printf("%d ",q[head]);
   }
   }
   利用單調隊列的單調性,如果頭不是最小就将頭更新,最大反之即可**
   
   **但對于區間查詢這類的問題線段樹一般都能過,這道題隻需要線段樹裡面的建樹,查詢點即可,呢麼學了線段樹單調隊列就沒用了麼,也不是的對于動态規劃裡面的優化,單調隊列也是很有用的,是以學了就有他的用處**      
**#include<cstdio>
#include<algorithm>
using namespace std;
#define N 1500000
#define ll long long
int a[N];
//資料類型不統一也會造成runtime error
struct node
{
    int l,r,maxx,minx;
} tree[4*N+10];
//更新
void update(int k)
{
    tree[k].maxx=max(tree[k*2].maxx,tree[k*2+1].maxx);
    tree[k].minx=min(tree[k*2].minx,tree[k*2+1].minx);
}
//建樹
void build(int k,int l,int r)
{
    tree[k].l=l,tree[k].r=r;
    if(l==r)
    {
        tree[k].maxx=a[l];
        tree[k].minx=a[l];
        return ;
    }
    int mid=(l+r)/2;
    build(k*2,l,mid);//左
    build(k*2+1,mid+1,r);//右
    update(k);
}
//查詢點
int query_max(int k,int l,int r)
{
    if(tree[k].l>=l&&tree[k].r<=r)
    {
        return tree[k].maxx;
    }
    int mid=(tree[k].l+tree[k].r)/2;
    if(mid>=r)
        return query_max(k*2,l,r);
    if(mid<l)
        return query_max(k*2+1,l,r);
    return max(query_max(k*2,l,r),query_max(k*2+1,l,r));
}
int query_min(int k,int l,int r)
{
    if(tree[k].l>=l&&tree[k].r<=r)
    {
        return tree[k].minx;
    }
    int mid=(tree[k].l+tree[k].r)/2;
    if(mid>=r)
        return query_min(k*2,l,r);
    if(mid<l)
        return query_min(k*2+1,l,r);
    return min(query_min(k*2,l,r),query_min(k*2+1,l,r));
}
int main()
{
int n,k;
scanf("%d %d",&n,&k);
for(int i=1;i<=n;i++)
{
 scanf("%d",&a[i]);
}
build(1,1,n);
for(int i=1;i<=n;i++)
{
     if(i+k-1>n)
        break;
    printf("%d ",query_min(1,i,i+k-1));
}
printf("\n");
for(int i=1;i<=n;i++)
{
     if(i+k-1>n)
        break;
    printf("%d ",query_max(1,i,i+k-1));
}
printf("\n");
}**