您的位置:首页 > 理论基础 > 数据结构算法

数据结构---各种树模板

2014-12-23 20:23 239 查看

1:Trie 字典树

字典树

又称单词查找树,Trie树,是一种树形结构,是一种哈希树的变种。典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:利用字符串的公共前缀来节约存储空间,最大限度地减少无谓的字符串比较,查询效率比哈希表高。

它有3个基本性质:根节点不包含字符,除根节点外每一个节点都只包含一个字符。 从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串。
每个节点的所有子节点包含的字符都不相同。
详细应用见 http://blog.csdn.net/metalseed/article/details/7953262

#include <iostream>    
using namespace std;    
#define MAX 26 //字符集大小    
    
typedef struct TrieNode {    
    int nCount;    
    struct TrieNode *next[MAX];    
}TrieNode;    
    
TrieNode Memory[1000000];    
int allocp =0;    
    
TrieNode *CreateTrieNode() {    
    int i;    
    TrieNode *p;    
    p = &Memory[allocp++];    
    p->nCount = 1;    
    for(i =0 ; i < MAX ; i++) {    
        p->next[i] = NULL;    
    }    
    return p;    
}    
    
void InsertTrie(TrieNode * &pRoot , char*s) {    
    int i, k;    
    TrieNode *p;    
    if(!(p = pRoot)) {    
        p = pRoot = CreateTrieNode();    
    }    
    i = 0;    
    while(s[i]) {    
        k = s[i++] - 'a';    
        if(p->next[k])    
            p->next[k]->nCount++;    
        else    
            p->next[k] = CreateTrieNode();    
        p = p->next[k];    
    }    
}    
/*查询该前缀出现次数*/    
/*若查询该词出现次数  
  则所有的count初始化为0  
  并去除所有对count的操作  
  只在每次InsertTrie末尾加 p->nCount++;   
*/     
int SearchTrie(TrieNode * &pRoot , char*s) {    
    TrieNode *p;    
    int i , k;    
    if(!(p = pRoot)) {    
        return 0;    
    }    
    i = 0;    
    while(s[i]) {    
        k = s[i++] -'a';    
        if(p->next[k] == NULL) return 0;    
        p = p->next[k];    
    }    
    return p->nCount;    
}    
    
int main()    
{    
    TrieNode *ROOT = NULL;    
    InsertTrie(ROOT,"see");    
    InsertTrie(ROOT,"seeda");    
    InsertTrie(ROOT,"seedb");    
    InsertTrie(ROOT,"seeda");    
    cout<<SearchTrie(ROOT,"seeda")<<endl;    
    cout<<SearchTrie(ROOT,"seedb")<<endl;    
    cout<<SearchTrie(ROOT,"see")<<endl;    
    return 0;    
}    

3:BIT 树状数组

1、概述

树状数组(binary indexed tree),是一种设计新颖的数组结构,它能够高效地获取数组中连续n个数的和。概括说,树状数组通常用于解决以下问题:数组{a}中的元素可能不断地被修改,怎样才能快速地获取连续几个数的和?

2、树状数组基本操作

传统数组(共n个元素)的元素修改和连续元素求和的复杂度分别为O(1)和O(n)。树状数组通过将线性结构转换成伪树状结构(线性结构只能逐个扫描元素,而树状结构可以实现跳跃式扫描),使得修改和求和复杂度均为O(lgn),大大提高了整体效率。
详见 :http://blog.csdn.net/metalseed/article/details/7984075   (含2D模板)

#include<iostream>    
#include<algorithm>    
using namespace std;    
    
    
    
/* 1D */       
const int maxn = 10000;      
int tree[maxn],maxID = 0xff/*数组长度,由题定,建树用update*/;      
      
inline void init()      
{      
    memset(tree,0,sizeof(tree));      
}      
      
inline int read(int idx){ /*求前idx项和*/      
    int sum = 0;      
    while (idx > 0){      
        sum += tree[idx];      
        idx -= (idx & -idx);      
    }      
    return sum;      
}      
    
inline int readSingle(int idx){ /*求idx单点值*/    
    int sum = tree[idx];    
    if (idx > 0){    
        int z = idx - (idx & -idx);    
        idx--;     
        while (idx != z){    
            sum -= tree[idx];     
            idx -= (idx & -idx);    
        }    
    }    
    return sum;    
}    
    
inline void update(int idx ,int val){  /*给idx位置叠加val,叠加!*/     
    while (idx <= maxID){      
        tree[idx] += val;      
        idx += (idx & -idx);      
    }      
}     
    
    
    
int main()    
{    
    cout << read(10) << endl;    
    for(int i = 0; i< 10; ++i)    
    {    
        update(i+1,i+1);    
    }    
    update(4,999);    
    cout << read(1) << endl;    
    cout << read(3) << endl;    
        
    cout << readSingle(4) << endl;    
    return 0;    
}    

4:Segment Tree 线段树

成段加C  区间求和

#include <cstdio>    
#include <algorithm>    
using namespace std;    
     
#define lson l , m , rt << 1    
#define rson m + 1 , r , rt << 1 | 1    
#define LL long long    
const int maxn = 111111;    
  
/* Node Begin */  
LL add[maxn<<2];    
LL sum[maxn<<2];    
/* Node End */  
  
void PushUp(int rt) {    
    sum[rt] = sum[rt<<1] + sum[rt<<1|1];    
}    
void PushDown(int rt,int m) {    
    if (add[rt]) {    
        add[rt<<1] += add[rt];    
        add[rt<<1|1] += add[rt];    
        sum[rt<<1] += add[rt] * (m - (m >> 1));    
        sum[rt<<1|1] += add[rt] * (m >> 1);    
        add[rt] = 0;    
    }    
}    
void build(int l,int r,int rt) {    
    add[rt] = 0;    
    if (l == r) {    
        scanf("%lld",&sum[rt]);    
        return ;    
    }    
    int m = (l + r) >> 1;    
    build(lson);    
    build(rson);    
    PushUp(rt);    
}    
void update(int L,int R,int c,int l,int r,int rt) {    
    if (L <= l && r <= R) {    
        add[rt] += c;    
        sum[rt] += (LL)c * (r - l + 1);    
        return ;    
    }    
    PushDown(rt , r - l + 1);    
    int m = (l + r) >> 1;    
    if (L <= m) update(L , R , c , lson);    
    if (m < R) update(L , R , c , rson);    
    PushUp(rt);    
}    
LL query(int L,int R,int l,int r,int rt) {    
    if (L <= l && r <= R) {    
        return sum[rt];    
    }    
    PushDown(rt , r - l + 1);    
    int m = (l + r) >> 1;    
    LL ret = 0;    
    if (L <= m) ret += query(L , R , lson);    
    if (m < R) ret += query(L , R , rson);    
    return ret;    
}    
int main() {    
    int N , Q;    
    scanf("%d%d",&N,&Q);    
    build(1 , N , 1);    
    while (Q --) {    
        char op[2];    
        int a , b , c;    
        scanf("%s",op);    
        if (op[0] == 'Q')   
        {    
            scanf("%d%d",&a,&b);    
            printf("%lld\n",query(a , b , 1 , N , 1));    
        }   
        else   
        {    
            scanf("%d%d%d",&a,&b,&c);    
            update(a , b , c , 1 , N , 1);    
        }    
    }    
    return 0;    
}    

5:SBT 二叉平衡检索树

http://acm.hdu.edu.cn/showproblem.php?pid=4006

#include <stdio.h>  
#include <string.h>  
#define MAX 1000010  
  
  
int n,m;  
struct SBT {  
  
    int left,right,size,key;  
    void Init() {  
  
        left = right = 0;  
        size = 1;  
    }  
}a[MAX];  
int tot,root;  
  
  
void left_rotate(int &t) {  
  
    int k = a[t].right;  
    a[t].right = a[k].left;  
    a[k].left = t;  
    a[k].size = a[t].size;  
    a[t].size = a[a[t].left].size + a[a[t].right].size + 1;  
    t = k;  
}  
void right_rotate(int &t) {  
  
    int k = a[t].left;  
    a[t].left = a[k].right;  
    a[k].right = t;  
    a[k].size = a[t].size;  
    a[t].size = a[a[t].left].size + a[a[t].right].size + 1;  
    t = k;  
}  
void maintain(int &t,int flag) {  
  
    if (flag == 0) {  
  
        if (a[a[a[t].left].left].size > a[a[t].right].size)   
            right_rotate(t);  
        else if (a[a[a[t].left].right].size > a[a[t].right].size)  
            left_rotate(a[t].left),right_rotate(t);  
        else return;  
    }  
    else {  
  
        if (a[a[a[t].right].right].size > a[a[t].left].size)  
            left_rotate(t);  
        else if (a[a[a[t].right].left].size > a[a[t].left].size)  
            right_rotate(a[t].right),left_rotate(t);  
        else return;  
    }  
    maintain(a[t].left,0);  
    maintain(a[t].right,1);  
    maintain(t,0);  
    maintain(t,1);  
}  
void insert(int &t,int v) {  
  
    if (t == 0)  
        t = ++tot,a[t].Init(),a[t].key = v;  
    else {  
  
        a[t].size++;  
        if (v < a[t].key)  
            insert(a[t].left,v);  
        else insert(a[t].right,v);  
        maintain(t,v>=a[t].key);  
    }  
}  
int del(int &t,int v) {  
  
    if (!t) return 0;  
    a[t].size--;  
  
    if (v == a[t].key || v < a[t].key && !a[t].left  
        || v > a[t].key && !a[t].right) {  
  
        if (a[t].left && a[t].right) {  
  
            int p = del(a[t].left,v+1);  
            a[t].key = a[p].key;  
            return p;  
        }  
        else {  
  
            int p = t;  
            t = a[t].left + a[t].right;  
            return p;  
        }  
    }  
    else return del(v<a[t].key?a[t].left:a[t].right,v);  
}  
int find(int t,int k) {  
  
    if (k <= a[a[t].left].size)  
        return find(a[t].left,k);  
    if (k > a[a[t].left].size + 1)  
        return find(a[t].right,k-a[a[t].left].size-1);  
    return a[t].key;  
}  
  
  
int main()  
{  
    int i,j,k;  
  
  
    while (scanf("%d%d",&n,&m) != EOF) {  
  
        tot = root = 0;  
        char ope[10];  
        while (n--) {  
  
            scanf("%s",ope);  
            if (ope[0] == 'I') {  
  
                scanf("%d",&k);  
                insert(root,k);  
            }  
            else printf("%d\n",find(root,a[root].size+1-m));  
        }  
    }  
}  

6:Splay 伸展树

/* 
题意:有N个数字围成一个圈,有M个操作,操作类型有六种: 
(1)“add x",从当前指针位置开始的顺时针K2个数加上x。 
(2)"reverse",翻转,从当前指针指针位置开始的顺时针的K2个数。 
(3)"insert x",在当前指针位置的顺时候方向插入一个数x。 
(4)”delete“,删除当前指针所指的数。 
(5)"move x”,如果x=1,指针逆时针旋转,如果x=2,顺时针旋转。 
(6)“query",查询指针所指向的数的值。 
Splay的作法就不说了。 
还可以有三个双端队列加两个标记搞定,方法,是第一个双端队列que1维护前K1个数, 
第二个que2维护第K1+1到第K2个数,第三个que3维护接下的数,标记add, 
表示que1和que2里的数要加上多少,标记head,表示que1是否被翻转过。 
Splay(姿势1): 
*/  
#include <iostream>  
#include <cstdio>  
#include <cstring>  
#include <string>  
#include <vector>  
#include <algorithm>  
#include <queue>  
#include <set>  
#include <map>  
using namespace std;  
  
typedef long long LL;  
typedef pair<int,int> PII;  
  
#define LL(x)    (ch[x][0])  
#define RR(x)    (ch[x][1])  
#define Kt       (ch[ ch[Rt][1] ][0])  
#define MID(a,b) (a+((b-a)>>1))  
  
const int N=1e6+5;  
  
int n,m,k1,k2;  
int a[N/2];  
  
struct SplayTree  
{  
    int Rt,top;  
    int pre
,sz
,ch
[2];  
  
    int key
,add
,pos;  
    bool flip
;  
  
    inline void Link(int x,int y,int f)  
    {  
        pre[x]=y; if(y) ch[y][f]=x;  
    }  
    inline void Rotate(int x,int f)  
    {  
        int y=pre[x],z=pre[y];  
  
        PushDown(y); PushDown(x);  
  
        Link(x,z,RR(z)==y);  
        Link(ch[x][f],y,!f);  
        Link(y,x,f);  
  
        PushUp(y);  
    }  
    inline void Splay(int x,int goal)  
    {  
        while(pre[x]!=goal)  
        {  
            int y=pre[x],z=pre[y];  
            int cx=(LL(y)==x),cy=(LL(z)==y);  
            if(z==goal) Rotate(x,cx);  
            else  
            {  
                if(cx==cy) Rotate(y,cy);  
                else Rotate(x,cx);  
                Rotate(x,cy);  
            }  
        }  
        PushUp(x);  
        if(goal==0) Rt=x;  
    }  
    inline void Select(int K,int goal)  
    {  
        int x=Rt;  
        PushDown(x);  
        while(1)  
        {  
            if(sz[LL(x)]>=K) x=LL(x);  
            else if(sz[LL(x)]+1==K) break;  
            else K-=sz[LL(x)]+1,x=RR(x);  
            PushDown(x);  
        }  
        Splay(x,goal);  
    }  
  
    inline void fun_add(int x,int valu)  
    {  
        add[x]+=valu;  
        key[x]+=valu;  
    }  
    inline void fun_flip(int x)  
    {  
        flip[x]^=1;  
        swap(LL(x),RR(x));  
    }  
    inline void PushDown(int x)  
    {  
        if(add[x])  
        {  
            fun_add(LL(x),add[x]);  
            fun_add(RR(x),add[x]);  
            add[x]=0;  
        }  
        if(flip[x])  
        {  
            fun_flip(LL(x));  
            fun_flip(RR(x));  
            flip[x]=0;  
        }  
    }  
    inline void PushUp(int x)  
    {  
        sz[x]=1+sz[LL(x)]+sz[RR(x)];  
    }  
    inline void Add(int x)  
    {  
        Select(1,0); Select(k2+2,Rt);  
        fun_add(Kt,x);  
    }  
    inline void Reverse()  
    {  
        Select(1,0); Select(k1+2,Rt);  
        fun_flip(Kt);  
    }  
    inline void Insert(int x,int pos)  
    {  
        Select(pos,0); Select(pos+1,Rt);  
        addNode(x,Kt,RR(Rt));  
        PushUp(RR(Rt)); PushUp(Rt);  
    }  
    inline int Delete(bool top)  
    {  
        int valu;  
        if(top)  
        {  
            Select(1,0);    Select(3,Rt);  
            valu=key[Kt];  
            Kt=0;  
            PushUp(RR(Rt)); PushUp(Rt);  
        }  
        else  
        {  
            int len=sz[Rt];  
            Select(len-2,0);Select(len,Rt);  
            valu=key[Kt];  
            Kt=0;  
            PushUp(RR(Rt)); PushUp(Rt);  
        }  
        return valu;  
    }  
    inline void Move(int x)  
    {  
        if(x==1)  
        {  
            int valu=Delete(0);  
            Insert(valu,1);  
        }  
        else  
        {  
            int valu=Delete(1);  
            Insert(valu,sz[Rt]-1);  
        }  
    }  
    inline void Query()  
    {  
        Select(2,0);  
        printf("%d\n",key[Rt]);  
    }  
  
//    void Debug(){ printf("Rt:%d\n",Rt); Travel(Rt); }  
//    void Travel(int x)  
//    {  
//        if(x==0) return;  
//  
//        PushDown(x);  
//        Travel(LL(x));  
//        printf("node:%d,pre:%d,sz:%d,LL:%d,RR:%d,key:%d\n",  
//               x,pre[x],sz[x],LL(x),RR(x),key[x]);  
//        Travel(RR(x));  
//    }  
  
    void addNode(int valu,int &x,int f)  
    {  
        x=++top;  
        pre[x]=f; sz[x]=1; LL(x)=RR(x)=0;  
  
        key[x]=valu; add[x]=flip[x]=0;  
    }  
    void build(int lft,int rht,int &x,int f)  
    {  
        if(lft>rht) return;  
  
        int mid=MID(lft,rht);  
        addNode(a[mid],x,f);  
        build(lft,mid-1,LL(x),x);  
        build(mid+1,rht,RR(x),x);  
        PushUp(x);  
    }  
    void init()  
    {  
        Rt=top=0;  
        pre[0]=sz[0]=LL(0)=RR(0)=0;  
  
        addNode(0,Rt,0);    addNode(0,RR(Rt),Rt);  
        build(0,n-1,Kt,RR(Rt));  
        PushUp(RR(Rt));     PushUp(Rt);  
    }  
}spt;  
int main()  
{  
    int t_cnt=0;  
    while(scanf("%d%d%d%d",&n,&m,&k1,&k2)!=EOF)  
    {  
        if(n==0&&m==0&&k1==0&&k2==0) break;  
  
        for(int i=0;i<n;i++) scanf("%d",&a[i]);  
  
        spt.init();  
  
        printf("Case #%d:\n",++t_cnt);  
  
        char op[100]; int x;  
        while(m--)  
        {  
            scanf("%s",op);  
            if(op[0]=='a')  
            {  
                scanf("%d",&x); spt.Add(x);  
            }  
            else if(op[0]=='r') spt.Reverse();  
            else if(op[0]=='i')  
            {  
                scanf("%d",&x); spt.Insert(x,2);  
            }  
            else if(op[0]=='d') spt.Delete(1);  
            else if(op[0]=='m')  
            {  
                scanf("%d",&x); spt.Move(x);  
            }  
            else spt.Query();  
        }  
    }  
    return 0;  
}  
  
  
Spaly(姿势2):  
  
#include <iostream>  
#include <cstdio>  
#include <cstring>  
using namespace std;  
  
#define LL(x) (ch[x][0])  
#define RR(x) (ch[x][1])  
#define Kt    (ch[ ch[Rt][1] ][0])  
#define MID(a,b)   (a+((b-a)>>1))  
  
const int N=1e6+5;  
  
int a[N/2];  
int n,m,K1,K2,pos;  
  
struct SplayTree  
{  
    int Rt,top;  
    int sz
,pre
,ch
[2];  
  
    bool flip
;  
    int key
,add
;  
  
    inline void Link(int x,int y,int f)  
    {  
        pre[x]=y; if(y) ch[y][f]=x;  
    }  
    inline void Rotate(int x,int f)  
    {  
        int y=pre[x],z=pre[y];  
  
        PushDown(y); PushDown(x);  
        Link(x,z,RR(z)==y);  
        Link(ch[x][f],y,!f);  
        Link(y,x,f);  
        PushUp(y);  
    }  
    inline void Splay(int x,int goal)  
    {  
        while(pre[x]!=goal)  
        {  
            int y=pre[x],z=pre[y];  
            int cx=(LL(y)==x),cy=(LL(z)==y);  
            if(z==goal) Rotate(x,cx);  
            else  
            {  
                if(cx==cy) Rotate(y,cy);  
                else Rotate(x,cx);  
                Rotate(x,cy);  
            }  
        }  
        PushUp(x);  
        if(goal==0) Rt=x;  
    }  
    inline void Select(int K,int goal)  
    {  
        int x=Rt;  
        PushDown(x);  
        while(1)  
        {  
            if(sz[LL(x)]>=K) x=LL(x);  
            else if(1+sz[LL(x)]==K) break;  
            else K-=sz[LL(x)]+1,x=RR(x);  
            PushDown(x);  
        }  
        Splay(x,goal);  
    }  
  
    inline void fun_add(int x,int valu)  
    {  
        key[x]+=valu;  
        add[x]+=valu;  
    }  
    inline void fun_flip(int x)  
    {  
        flip[x]^=1;  
        swap(LL(x),RR(x));  
    }  
    inline void PushUp(int x)  
    {  
        sz[x]=1+sz[LL(x)]+sz[RR(x)];  
    }  
    inline void PushDown(int x)  
    {  
        if(add[x])  
        {  
            fun_add(LL(x),add[x]);  
            fun_add(RR(x),add[x]);  
            add[x]=0;  
        }  
        if(flip[x])  
        {  
            fun_flip(LL(x)); fun_flip(RR(x));  
            flip[x]=0;  
        }  
    }  
    inline void Add(int st,int ed,int valu)  
    {  
        Select(st-1,0); Select(ed+1,Rt);  
        fun_add(Kt,valu);  
    }  
    inline void Reverse(int st,int ed)  
    {  
        Select(st-1,0); Select(ed+1,Rt);  
        fun_flip(Kt);  
    }  
    inline void Insert(int pos,int valu)  
    {  
        Select(pos,0);  Select(pos+1,Rt);  
        addNode(valu,Kt,RR(Rt));  
        PushUp(RR(Rt)); PushUp(Rt);  
    }  
    inline void Delete(int pos)  
    {  
        Select(pos-1,0); Select(pos+1,Rt);  
        Kt=0;  PushUp(RR(Rt)); PushUp(Rt);  
    }  
    inline void Query(int pos)  
    {  
        Select(pos,0);  
        printf("%d\n",key[Rt]);  
    }  
    inline void Move(int len)  
    {  
        pos-=len;  
        Select(1,0);    Select(2+len,Rt);  
        int r1=Kt;      Kt=0;  
        PushUp(RR(Rt)); PushUp(Rt);  
  
        Select(sz[Rt]-1,0); Select(sz[Rt],Rt);  
        Link(r1,RR(Rt),0);  
        PushUp(RR(Rt)); PushUp(Rt);  
    }  
  
    inline void addNode(int valu,int &x,int f)  
    {  
        x=++top;  
  
        sz[x]=1; pre[x]=f; LL(x)=RR(x)=0;  
  
        key[x]=valu; add[x]=flip[x]=0;  
    }  
    void build(int lft,int rht,int &x,int f)  
    {  
        if(lft>rht) return;  
  
        int mid=MID(lft,rht);  
        addNode(a[mid],x,f);  
        build(lft,mid-1,LL(x),x);  
        build(mid+1,rht,RR(x),x);  
        PushUp(x);  
    }  
    void init()  
    {  
        Rt=top=0;  
  
        addNode(0,Rt,0); addNode(0,RR(Rt),Rt);  
  
        build(0,n-1,Kt,RR(Rt));  
        PushUp(RR(Rt));  PushUp(Rt);  
    }  
  
//    void Debug(){ printf("Rt:%d\n",Rt); Travel(Rt); }  
//    void Travel(int x)  
//    {  
//        if(x==0) return;  
//        PushDown(x);  
//        Travel(LL(x));  
//        printf("node:%d,sz:%d,pre:%d,LL:%d,RR:%d,key:%d\n",  
//               x,sz[x],pre[x],LL(x),RR(x),key[x]);  
//        Travel(RR(x));  
//    }  
}spt;  
void deal(int &pos,int len)  
{  
    if(pos<=1) pos=len-1;  
    if(pos>=len) pos=2;  
}  
int main()  
{  
    freopen("in.txt","r",stdin);  
  
    int t_cnt=0;  
    while(scanf("%d%d%d%d",&n,&m,&K1,&K2)!=EOF)  
    {  
        if(n==0&&m==0&&K1==0&&K2==0) break;  
  
        for(int i=0;i<n;i++) scanf("%d",&a[i]);  
  
        spt.init(); pos=2;  
  
        printf("Case #%d:\n",++t_cnt);  
  
        char op[100]; int x;  
        while(m--)  
        {  
            int len=spt.sz[spt.Rt];  
            scanf("%s",op);  
            if(op[0]=='a')  
            {  
                scanf("%d",&x);  
                if(pos+K2>len) spt.Move(pos+K2-len);  
                spt.Add(pos,pos+K2-1,x);  
            }  
            else if(op[0]=='r')  
            {  
                if(pos+K1>=len) spt.Move(pos+K1-len);  
                spt.Reverse(pos,pos+K1-1);  
            }  
            else if(op[0]=='i')  
            {  
                scanf("%d",&x); spt.Insert(pos,x);  
            }  
            else if(op[0]=='d')  
            {  
                spt.Delete(pos);  
                deal(pos,spt.sz[spt.Rt]);  
            }  
            else if(op[0]=='m')  
            {  
                scanf("%d",&x);  
                if(x==1) pos--;  
                else pos++;  
                deal(pos,len);  
            }  
            else if(op[0]=='q') spt.Query(pos);  
//            spt.Debug();  
        }  
    }  
    return 0;  
}  
  
  
/* 
Description 
 
You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type of operation is to add some given number to each number in a given interval. The other is to ask for the sum of numbers in a given interval. 
 
Input 
 
The first line contains two numbers N and Q. 1 ≤ N,Q ≤ 100000. 
The second line contains N numbers, the initial values of A1, A2, ... , AN. -1000000000 ≤ Ai ≤ 1000000000. 
Each of the next Q lines represents an operation. 
"C a b c" means adding c to each of Aa, Aa+1, ... , Ab. -10000 ≤ c ≤ 10000. 
"Q a b" means querying the sum of Aa, Aa+1, ... , Ab. 
 
Output 
 
You need to answer all Q commands in order. One answer in a line. 
 
Sample Input 
 
10 5 
1 2 3 4 5 6 7 8 9 10 
Q 4 4 
Q 1 10 
Q 2 4 
C 3 6 3 
Q 2 4 
Sample Output 
 

55 

15  http://acm.pku.edu.cn/JudgeOnline/problem?id=3468  区间跟新,区间求和 
*/  
#include <cstdio>  
#define keyTree (ch[ ch[root][1] ][0])  
const int maxn = 222222;  
struct SplayTree{  
    int sz[maxn];  
    int ch[maxn][2];  
    int pre[maxn];  
    int root , top1 , top2;  
    int ss[maxn] , que[maxn];  
   
    inline void Rotate(int x,int f) {  
        int y = pre[x];  
        push_down(y);  
        push_down(x);  
        ch[y][!f] = ch[x][f];  
        pre[ ch[x][f] ] = y;  
        pre[x] = pre[y];  
        if(pre[x]) ch[ pre[y] ][ ch[pre[y]][1] == y ] = x;  
        ch[x][f] = y;  
        pre[y] = x;  
        push_up(y);  
    }  
    inline void Splay(int x,int goal) {  
        push_down(x);  
        while(pre[x] != goal) {  
            if(pre[pre[x]] == goal) {  
                Rotate(x , ch[pre[x]][0] == x);  
            } else {  
                int y = pre[x] , z = pre[y];  
                int f = (ch[z][0] == y);  
                if(ch[y][f] == x) {  
                    Rotate(x , !f) , Rotate(x , f);  
                } else {  
                    Rotate(y , f) , Rotate(x , f);  
                }  
            }  
        }  
        push_up(x);  
        if(goal == 0) root = x;  
    }  
    inline void RotateTo(int k,int goal) {//把第k位的数转到goal下边  
        int x = root;  
        push_down(x);  
        while(sz[ ch[x][0] ] != k) {  
            if(k < sz[ ch[x][0] ]) {  
                x = ch[x][0];  
            } else {  
                k -= (sz[ ch[x][0] ] + 1);  
                x = ch[x][1];  
            }  
            push_down(x);  
        }  
        Splay(x,goal);  
    }  
    inline void erase(int x) {//把以x为祖先结点删掉放进内存池,回收内存  
        int father = pre[x];  
        int head = 0 , tail = 0;  
        for (que[tail++] = x ; head < tail ; head ++) {  
            ss[top2 ++] = que[head];  
            if(ch[ que[head] ][0]) que[tail++] = ch[ que[head] ][0];  
            if(ch[ que[head] ][1]) que[tail++] = ch[ que[head] ][1];  
        }  
        ch[ father ][ ch[father][1] == x ] = 0;  
        pushup(father);  
    }  
    //以上一般不修改//////////////////////////////////////////////////////////////////////////////  
    void debug() {printf("%d\n",root);Treaval(root);}  
    void Treaval(int x) {  
        if(x) {  
            Treaval(ch[x][0]);  
            printf("结点%2d:左儿子 %2d 右儿子 %2d 父结点 %2d size = %2d ,val = %2d\n",x,ch[x][0],ch[x][1],pre[x],sz[x],val[x]);  
            Treaval(ch[x][1]);  
        }  
    }  
    //以上Debug  
   
   
    //以下是题目的特定函数:  
    inline void NewNode(int &x,int c) {  
        if (top2) x = ss[--top2];//用栈手动压的内存池  
        else x = ++top1;  
        ch[x][0] = ch[x][1] = pre[x] = 0;  
        sz[x] = 1;  
   
        val[x] = sum[x] = c;/*这是题目特定函数*/  
        add[x] = 0;  
    }  
   
    //把延迟标记推到孩子  
    inline void push_down(int x) {/*这是题目特定函数*/  
        if(add[x]) {  
            val[x] += add[x];  
            add[ ch[x][0] ] += add[x];  
            add[ ch[x][1] ] += add[x];   
            sum[ ch[x][0] ] += (long long)sz[ ch[x][0] ] * add[x];  
            sum[ ch[x][1] ] += (long long)sz[ ch[x][1] ] * add[x];  
            add[x] = 0;  
        }  
    }  
    //把孩子状态更新上来  
    inline void push_up(int x) {      
        sz[x] = 1 + sz[ ch[x][0] ] + sz[ ch[x][1] ];  
        /*这是题目特定函数*/  
        sum[x] = add[x] + val[x] + sum[ ch[x][0] ] + sum[ ch[x][1] ];  
    }  
   
    /*初始化*/  
    inline void makeTree(int &x,int l,int r,int f) {  
        if(l > r) return ;  
        int m = (l + r)>>1;  
        NewNode(x , num[m]);        /*num[m]权值改成题目所需的*/  
        makeTree(ch[x][0] , l , m - 1 , x);  
        makeTree(ch[x][1] , m + 1 , r , x);  
        pre[x] = f;  
        push_up(x);  
    }  
    inline void init(int n) {/*这是题目特定函数*/  
        ch[0][0] = ch[0][1] = pre[0] = sz[0] = 0;  
        add[0] = sum[0] = 0;  
   
        root = top1 = 0;  
        //为了方便处理边界,加两个边界顶点  
        NewNode(root , -1);  
        NewNode(ch[root][1] , -1);  
        pre[top1] = root;  
        sz[root] = 2;  
   
   
        for (int i = 0 ; i < n ; i ++) scanf("%d",&num[i]);  
        makeTree(keyTree , 0 , n-1 , ch[root][1]);  
        push_up(ch[root][1]);  
        push_up(root);  
    }  
    /*更新*/  
    inline void update( ) {/*这是题目特定函数*/  
        int l , r , c;  
        scanf("%d%d%d",&l,&r,&c);  
        RotateTo(l-1,0);  
        RotateTo(r+1,root);       
        add[ keyTree ] += c;  
        sum[ keyTree ] += (long long)c * sz[ keyTree ];  
    }  
    /*询问*/  
    inline void query() {/*这是题目特定函数*/  
        int l , r;  
        scanf("%d%d",&l,&r);  
        RotateTo(l-1 , 0);  
        RotateTo(r+1 , root);  
        printf("%lld\n",sum[keyTree]);  
    }  
   
   
    /*这是题目特定变量*/  
    int num[maxn];  
    int val[maxn];  
    int add[maxn];  
    long long sum[maxn];  
}spt;  
   
   
int main() {  
    int n , m;  
    scanf("%d%d",&n,&m);  
    spt.init(n);  
    while(m --) {  
        char op[2];  
        scanf("%s",op);  
        if(op[0] == 'Q') {  
            spt.query();  
        } else {  
            spt.update();  
        }  
    }  
    return 0;  
}  

7:动态树

8:斯坦纳树

9:主席树

10:QTree
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: