
1 #include<iostream> 2 #include<stdio.h> 3 using namespace std; 4 struct node{ 5 int r; //root to the right's range 6 int l; 7 node * rt; //the subtree of root's right 8 node * lt; 9 __int64 key; //the value of the root, means the sum of all the leaves of the root 10 }; 11 node * buildtree(int left,node * root,int right){ //build a tree than can from left to right 12 root->l=left; 13 root->r=right; 14 int temp=(left+right)/2; 15 if(left==right){ //build the leaf of the tree 16 root->lt=NULL; 17 root->rt=NULL; 18 root->key=0; //made the key of root to 0 19 return root; 20 } 21 else { 22 node * newleft; 23 newleft=new node; 24 root->lt=newleft; 25 root->key=0; 26 buildtree(left,newleft,temp); // constract the left subtree of root 27 node * newright; 28 newright=new node; 29 root->rt=newright; 30 root->key=0; 31 buildtree(temp+1,newright,right); //constract the right subtree of the root 32 } 33 return root; 34 } 35 __int64 insert(int point,node * root1,int real){ //insert a value real to a leaf point and sum up to the while tree 36 int temp1=(root1->l+root1->r)/2; 37 long long re1=0,re2=0; 38 if(point==root1->l&&point==root1->r){ 39 root1->key+=real; 40 return root1->key; 41 } 42 else if(point>=root1->l&&point<=temp1){ 43 re1=insert(point,root1->lt,real); 44 root1->key=(re1+(root1->rt->key)); 45 return root1->key; 46 } 47 else { 48 re2=insert(point,root1->rt,real); 49 root1->key=(re2+(root1->lt->key)); 50 return root1->key; 51 } 52 } 53 __int64 findsum(int left1,int right1,node * root3){ //find the sum of value from left leaf to right leaf 54 if(left1==root3->l&&right1==root3->r){ 55 return root3->key; 56 } 57 __int64 temp3; 58 int temp2=(root3->l+root3->r)/2; 59 if(left1>=root3->l&&right1<=temp2){ 60 temp3=findsum(left1,right1,root3->lt); 61 } 62 else if(left1>=temp2+1&&right1<=root3->r){ 63 temp3=findsum(left1,right1,root3->rt); 64 } 65 else if(left1<=temp2&&right1>=temp2+1){ 66 temp3=findsum(left1,temp2,root3->lt)+findsum(temp2+1,right1,root3->rt); 67 return temp3; 68 } 69 return temp3; 70 } 71 int main(){ 72 int n1,n2; 73 while(scanf("%d%d",&n1,&n2)!=EOF){ 74 node * newtree; 75 newtree=new node; //build a root 76 buildtree(1,newtree,n1); // build a tree 77 for(int g=1;g<=n1;g++){ 78 int tep3; 79 getchar(); 80 scanf("%d",&tep3); 81 insert(g,newtree,tep3); //insert a value to the leaf 82 } 83 for(int i=1;i<=n2;i++){ 84 char temp4; 85 getchar(); 86 scanf("%c",&temp4); 87 if(temp4=='C'){ 88 int temp5,temp7; 89 getchar(); 90 scanf("%d%d",&temp5,&temp7); 91 insert(temp5,newtree,temp7); //insert the value temp7 to the leaf point temp7 92 } 93 else if(temp4=='Q'){ 94 getchar(); 95 int tep1,tep2; 96 scanf("%d%d",&tep1,&tep2); 97 __int64 tep5=findsum(tep1,tep2,newtree); //find tne sum of leaf from tep1 to tmp2 98 printf("%I64d\n",tep5); 99 } 100 } 101 getchar(); 102 } 103 return 0; 104 }
线段数主要用于更新的值影响区间的值,以及常常要求查找区间的性质时,为节省时间用到的结构。
其中二分的思想十分重要
描述:
输入点集数以及要求数。
C a b 为将b值加入到叶子节点a中,
Q a b 为求点集a到b的总和。
方法:
建立一棵二叉平衡树。每一个节点都表示以其为根的叶子节点的值的总和。
所以针对该题,该二叉树有三个操作:构造树(根据一开始的要求,即一共有多少个点集来构造);插入值(将值加到对应的叶子节点中,并且返回时更新根节点的值);求点集的和(在二叉树中找到对应的要求点集的根节点,有可能需要将要求分段查找,然后相加)。