字典树
又称单词查找树,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; }
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; }
成段加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; }
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)); } } }
/* 题意:有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[N],sz[N],ch[N][2]; int key[N],add[N],pos; bool flip[N]; 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[N],pre[N],ch[N][2]; bool flip[N]; int key[N],add[N]; 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 4 55 9 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