poj 3468 Splay 樹

來源:互聯網
上載者:User

標籤:blog   http   使用   os   io   for   art   問題   

大二上的時候,寫過一個AVL的操作示範,今天一看Splay,發現和AVL其實一樣,加上線段樹的基礎,懶惰標記什麼都知道,學起來輕鬆許多哦

我參考的模板來自這裡  http://blog.csdn.net/u013480600/article/list/2

裡面有大量的ch[r][0] ch[r][1]等 我建議用宏定義取代,寫的時候方括弧少打了很多,等做的題多得時候,我再把自己使用的模板發來


#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>using namespace std;/*===============================Splay樹模板1、tot1,tot2都是從1開始2、================================*/#define key_value ch[ch[root][1]][0]#define ls(r) ch[r][0]#define rs(r) ch[r][1]#define ll long long#define repe(i,s,e) for(int i=s;i<=e;i++)#define rep(i,s,e) for(int i=s;i<e;i++)const int MAXN=100000 +10;int pre[MAXN],ch[MAXN][2],sz[MAXN],root,tot1;//  父節點、左右孩子(0為左,同時0為左旋)、子樹規模、根節點、結點數量int key[MAXN];//結點的值int add[MAXN];ll sum[MAXN];//sum[i]=v 以i為root的樹的和,int s[MAXN],tot2;/////??????//記憶體池、記憶體池容量(這題用不到,如果有刪除操作,記憶體不夠可以這樣//s中存的是被回收的記憶體,從後面可以看到,tot2不為0的時候優先使用s[tot2]=x中的//pre[x],ch[x],size[x]等,//否則就使用tot1++之後產生的數x的對應位置int a[MAXN];//初始時的數組,建樹時用int n,q;void newnode(int &r,int father, int k)//r必須是&{    if(tot2)r=s[tot2--];//取得時候tot2--,存++tot2    else r=++tot1;    pre[r]=father;    sz[r]=1;    key[r]=k;    add[r]=sum[r]=0;    ch[r][0]=ch[r][1]=0;}void updateadd(int r, int av){    if(!r)return;//??    add[r]+=av;    key[r]+=av;    sum[r]+=(ll)av*sz[r];}//通過孩子結點更新父親結點void pushup(int r){    sz[r]=sz[ls(r)]+sz[rs(r)]+1;    sum[r]=sum[ls(r)]+sum[rs(r)]+key[r];}//將延遲標記更新到孩子結點void pushdown(int r){    if(add[r])    {        updateadd(ls(r),add[r]);        updateadd(rs(r),add[r]);        add[r]=0;    }}//建樹區間[l,r],先建立中間結點,再建兩端,//注意和線段樹的區別void build(int &x, int l, int r, int father){    if(l>r)return;    int mid=(l+r)/2;    newnode(x, father, a[mid]);    build(ch[x][0], l, mid-1, x);    build(ch[x][1], mid+1, r, x);    pushup(x);}//初始化,前後各加一個king結點void Init(){    for(int i=1;i<=n;i++)        scanf("%d",&a[i]);    root=tot1=tot2=0;    ls(root)=rs(root)=pre[root]=sz[root]=add[root]=sum[root]=key[root]=0;    newnode(root, 0, -1);//root'sfatheris -1    newnode(rs(root),root,-1);//頭尾各插入一個空    build(key_value, 1, n, rs(root));    pushup(rs(root));    pushup(root);}//旋轉,0為左旋,1為右旋 該部分基本固定void rota(int x, int kind){    int y=pre[x];    pushdown(y);    pushdown(x);//必須先把y的標記向下傳遞,在傳x    ch[y][!kind]=ch[x][kind],pre[ch[x][kind]]=y;    if(pre[y])//??y的父節點不是root        ch[pre[y]][ rs(pre[y])==y ]=x;//只能對這句牛逼的代碼說聲我屮艸芔茻    pre[x]=pre[y];    ch[x][kind]=y,pre[y]=x;    pushup(y);//維護y結點   x節點的資訊不用PushUp嗎?可以證明這裡除了x節點維護的資訊不對外,其他所有點資訊都正確    //Push_Up(x);//這個可以不寫,詳見Crash:運用伸展樹解決數列維護問題 論文,但是寫了也不會多多少時間消耗}void Splay(int r, int goal)//將r調整到goal下面{    pushdown(r);// 離開之前把懶惰標記的資訊傳遞    while(pre[r]!=goal)    {        if(pre[pre[r]]==goal)            rota(r, ch[pre[r]][0]==r);//r在左子樹,右旋        else        {            int y=pre[r];            int kind=ch[pre[y]][0]==y;            if(ch[y][kind]==r)//之字形旋轉            {//y在其父節點的左子樹上,r在y的右子樹上             //或者y在其父節點的右子樹,r在y左子樹                rota(r, !kind);                rota(r, kind);            }            else    //一字型旋轉            {                rota(y, kind);//注意這裡是y啊                rota(r, kind);            }        }    }    pushup(r);    if(goal==0)root=r;}//得到第k個結點編號int getkth(int r, int k){    pushdown(r);    int t=sz[ls(r)]+1;    if(t==k)return r;    if(t>k)return getkth(ls(r),k);//在左子樹第k個    else return getkth(rs(r), k-t);//在右子樹第k-t個}//得到以r為根的第一個結點--最左邊的節點編號int getmin(int r){    pushdown(r);    while(ls(r))    {        r=ls(r);        pushdown(r);    }    return r;}//得到以r為根的最後一個結點--最右邊的編號int getmax(int r){    pushdown(r);    while(rs(r))    {        r=rs(r);        pushdown(r);    }    return r;}void addv(int l, int r, int d){    Splay(getkth(root,l),0);    Splay(getkth(root,r+2),root);    updateadd(key_value, d);    pushup(rs(root));    pushup(root);}ll Querysum(int l, int r){    Splay(getkth(root, l),0);//第l個點到根結點    Splay(getkth(root, r+2), root);//第r+2個點到根結點的右孩子    return sum[key_value];}int main(){    //freopen("poj3468.txt","r",stdin);    int q;    while(~scanf("%d%d", &n, &q))    {        Init();        while(q--)        {            char op[30];            int x,y,z;            scanf("%s",op);            if(op[0]=='Q')            {                scanf("%d%d",&x,&y);                printf("%lld\n",Querysum(x,y));            }            else            {                scanf("%d%d%d",&x,&y,&z);                addv(x,y,z);            }        }    }    return 0;}


聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.