1. 程式人生 > >2017暑假訓練第二十天

2017暑假訓練第二十天

  今天早上的訓練研究了一下線段樹求最大值的演算法,建樹方法方法大致與模板相同,多了一個有關最大值的內容:

  tree[id].max=max(tree[2*id].tree[2*id+1]);

  意思也很好理解,就是根節點的最大值等於左子區間和右子區間的最大值的較大者,依舊是遞迴查詢型別。

  而後a了一道插入元素並查詢第k大數的題目,就是一開始建立一個空的樹,根據插入的元素與位置的關係向樹裡插入元素,並進行查詢。

  程式碼如下:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define maxn 1000005
using namespace std;
struct xtree{
    int l;
    int r;
    int val;
    int mid(){
        return (l+r)/2;
    }
};
struct xtree tree[maxn*3];
int n,m;
int pushup(int id){
    tree[id].val=tree[id*2].val+tree[id*2+1].val;
}
void build(int id,int l,int r){
    tree[id].l=l;
    tree[id].r=r;
    tree[id].val=0;
    if (tree[id].l==tree[id].r){
        return ;
    }
    int mm=tree[id].mid();
    build(id*2,l,mm);
    build(id*2+1,mm+1,r);
    pushup(id);
}
void update(int id,int l,int r,int pos){
    if (l==r){
        tree[id].val++;
        return ;
    }
    int mm=tree[id].mid();
    if (pos>mm)update(id*2+1,mm+1,r,pos);
    else update(id*2,l,mm,pos);
    pushup(id);
}
int query(int id,int l,int r,int pos){
    int re;
    if (l==r){
        return l;
    }
    else {
        int mm=tree[id].mid();
        if (pos>tree[id*2].val)re=query(id*2+1,mm+1,r,pos-tree[id*2].val);
        else re=query(id*2,l,mm,pos);
    }
    return re;
}
int main(){
    int i,j,k;
    while(scanf("%d%d",&n,&m)!=EOF){
        int sum=0;
        build(1,1,maxn);
        char str[2];
        int num;
        for(i=0;i<n;i++){
            scanf("%s",str);
            if(str[0]=='I'){
                sum++;
                scanf("%d",&num);
                update(1,1,n,num);
            }
            else if(str[0]=='Q'){
                int ans=query(1,1,maxn,sum-m+1);
                printf("%d\n",ans);
            }
        }
    }
}

  下午的比賽中做出了兩道關於圖論的題,一道是最小生成樹,一道是最短路徑,都是近乎於模板的題,而且題意十分明顯,但是略有遺忘,所以總錯在小的細節上,還需再行復習這裡的相關知識和細節。還看了最後一道題(一道簡單的貪心題)但是不是我做出來的。

  明天將繼續看有關於線段樹的知識點和題目的部落格。