POJ 3468 A Simple Problem with Integers -

来源:互联网 发布:数据库设计与开发规范 编辑:程序博客网 时间:2024/06/08 04:45

题目地址

一般求和首先想到就是每个结点保存sum的值代表这个区间的和

那么求区间的和就是找到[s,e]这个区间的结点并返回该sum值,复杂度为O(logn)

但是这样子有个不好的地方就是假如最坏的情况下把1~n区间都加c值,那么每个1~n的叶子结点都要遍历到且+c ,则时间复杂度就为O(nlogn)

于是就在结点中保存Inc这个值,表示该区间[s,e]每个数都加了c,那么上述情况复杂度就变为O(1);

如下:

struct CNode{   //此结点sum=(L-R+1)*Inc+nSum; int L,R;LL nSum,Inc;  //如果不设Inc,那么每次加数时都要更新到叶子节点 CNode *pLeft,*pRight;int Mid(){return (L+R)/2;}}tree[maxn*2];

那么区间加值和求和的方式就要改变下

区间[s,e]加c值:遍历到该区间,把该结点Inc+=c;  途中遇到的区间就nSum+=c*(e-s); 把+c产生的结果加上

求[s,e]和:到该区间就返回 (e-s+1)*Inc+nSum ,途中遇到的区间就顺便把nSum的值算出来=Inc*区间长度,并把该点Inc的累加到其儿子的区间


代码如下:

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int maxn=100000+5;typedef long long LL;struct CNode{   //此结点sum=(L-R+1)*Inc+nSum; int L,R;LL nSum,Inc;  //如果不设Inc,那么每次加数时都要更新到叶子节点 CNode *pLeft,*pRight;int Mid(){return (L+R)/2;}}tree[maxn*2];int cnt=0;void BuildTree(CNode *root,int L,int R){root->L=L;root->R=R;root->Inc=0;root->nSum=0;if(L==R) return;cnt++;root->pLeft=tree+cnt;cnt++;root->pRight=tree+cnt;int mid=root->Mid();BuildTree(root->pLeft,L,mid);BuildTree(root->pRight,mid+1,R);}void Insert(CNode *root,int i,int v){if(root->L==root->R){root->nSum=v;return;}root->nSum+=v;   //更新根节点的值; if(i<=root->Mid()) Insert(root->pLeft,i,v);else               Insert(root->pRight,i,v);}void Add(CNode *root,int L,int R,LL c){if(root->L==L&&root->R==R){root->Inc+=c;return;}int mid=root->Mid();root->nSum+=c*(R-L+1);if(R<=mid) Add(root->pLeft,L,R,c);else if(L>mid) Add(root->pRight,L,R,c);else {Add(root->pLeft,L,mid,c);Add(root->pRight,mid+1,R,c);}}LL Quary(CNode *root,int s,int e){if(root->L==s&&root->R==e){return root->nSum+root->Inc*(e-s+1);}root->nSum+=root->Inc*(root->R-root->L+1);int mid=root->Mid();Add(root->pLeft,root->L,mid,root->Inc);Add(root->pRight,mid+1,root->R,root->Inc);root->Inc=0; if(e<=mid)     return Quary(root->pLeft,s,e);else if(s>mid) return Quary(root->pRight,s,e);else return Quary(root->pLeft,s,mid)+Quary(root->pRight,mid+1,e);}int main(){int N,Q,v;scanf("%d%d",&N,&Q);BuildTree(tree,1,N);for(int i=1;i<=N;i++){scanf("%d",&v);Insert(tree,i,v);}char cmd[5];int s,e;for(int i=0;i<Q;i++){scanf("%s",cmd);if(cmd[0]=='Q') {scanf("%d%d",&s,&e);cout<<Quary(tree,s,e)<<endl;}else {scanf("%d%d%d",&s,&e,&v);Add(tree,s,e,v);}}return 0;} 




  

0 0
原创粉丝点击