/* 参考:http://hi.baidu.com/yy17yy/blog/item/3fbaaced633cc3cb2e2e21c8.html 线段树的变形,比赛的时候一直tle和mle交替,后附tle和mle的代码 和经典的线段树区间lazy操作相比,区间传递的是经验系数,每个点对系数的反应是不一样的,所以向下传递的时机有所改变,不但在区间被剖分时要向下释放,在该区间有某个点要升级的时候也要释放,因为此时用区间的lazy值叠加的话会影响结果,所以此时要释放lazy,lazy只有在这个区间的点都没到达升级门槛时才可以叠加。 优化后用c++跑出359ms,暂列hdu榜首,high~ tle的代码无疑是释放太频繁了导致延时操作没起多大作用 mle的代码是将每次的系数存入一个队列,这样就超出空间限制了 */ #include <iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #include<ctime> #include<map> #include<queue> #include<vector> using namespace std; const int N=10000; int n,m; int sum[12];//sum[i]从i升到i+1的门槛经验值 struct Node { int L,R;//区间左右边界 int level,exp;//本区间的最大等级和最大经验值 int min_dis;//本区间存在要升级点的最小经验系数 int lazy;//本区间还有多少经验系数没有释放到其子树 }tree[4*N]; inline void search_up(int t)//向上更新节点的信息 { int nl=2*t,nr=2*t+1; tree[t].exp=max(tree[nl].exp,tree[nr].exp); tree[t].level=max(tree[nl].level,tree[nr].level); tree[t].min_dis=min(tree[nl].min_dis,tree[nr].min_dis); } void create(int t,int L,int R)//建树 { tree[t].L=L; tree[t].R=R; tree[t].level=1; tree[t].exp=0; tree[t].min_dis=sum[1]/1;//sum[1]/1值为改变,这里/1为了突出tree[t].min_dis的意义,它不是所需经验而是所需经验系数 tree[t].lazy=0; int mid=(L+R)>>1; if(L<R) { create(t<<1,L,mid); create((t<<1)+1,mid+1,R); } } inline void down(int t)//将t的lazy值释放到其子树 { int nl=t<<1,nr=(t<<1)+1; tree[nl].exp+=tree[nl].level*tree[t].lazy; tree[nl].lazy+=tree[t].lazy; tree[nl].min_dis-=tree[t].lazy; tree[nr].exp+=tree[nr].level*tree[t].lazy; tree[nr].lazy+=tree[t].lazy; tree[nr].min_dis-=tree[t].lazy; tree[t].lazy=0; } void update(int t,int L,int R,int val) { int mid=(tree[t].R+tree[t].L)>>1,nl=t<<1,nr=(t<<1)+1; if(tree[t].L==tree[t].R)//如果为叶子节点,更新其等级、经验和min_dis { tree[t].exp+=tree[t].level*val; while(tree[t].exp>=sum[tree[t].level]) tree[t].level++; tree[t].min_dis=(sum[tree[t].level]-tree[t].exp)/tree[t].level+((sum[tree[t].level]-tree[t].exp)%tree[t].level!=0); return ; } if(tree[t].L==L&&tree[t].R==R) { if(val>=tree[t].min_dis)//本区间有点要升级,释放区间的lazy { down(t); update(nl,tree[nl].L,tree[nl].R,val);//将本次系数下放,递归到区间没有点要升级或叶子节点为止 update(nr,tree[nr].L,tree[nr].R,val); search_up(t);//向上维护t的信息 } else //本区间没有要升级的点 { tree[t].exp+=tree[t].level*val; tree[t].min_dis-=val; tree[t].lazy+=val; } return ; } if(tree[t].lazy)//向下松弛操作 { down(t); } if(R<=mid) update(nl,L,R,val); else if(L>mid) update(nr,L,R,val); else { update(nl,L,mid,val);update(nr,mid+1,R,val);} search_up(t);//每次update后必有search_up,因为t的子节点更新后,t的exp,level,dis_min都有可能改变 } int query(int t,int L,int R) { int nl=t<<1,nr=(t<<1)+1; int mid=(tree[t].R+tree[t].L)>>1,tmp; if(tree[t].L==L&&tree[t].R==R) { return tree[t].exp; } if(tree[t].lazy)//向下松弛操作 { down(t); } if(R<=mid)tmp=query(nl,L,R); else if(L>mid)tmp=query(nr,L,R); else {tmp=max(query(nl,L,mid),query(nr,mid+1,R));} return tmp; } //优化输入 inline int nextInt() { char c; while (c = getchar(), c < '0' || c > '9'); int r = c - '0'; while (c = getchar(), c >= '0' && c <= '9') r = r * 10 + c - '0'; return r; } int main() { int L,R,Case,de,ti,temp; char op[3]; Case=nextInt(); for(int k=1;k<=Case;k++) { n=nextInt(); de=nextInt(); ti=nextInt(); sum[0]=0; for(int i=1;i<de;i++) { sum[i]=nextInt(); } sum[de]=1<<30; create(1,1,n); printf("Case %d:\n",k); while(ti--) { scanf("%s",op); L=nextInt(); R=nextInt(); if(op[0]=='Q') { printf("%d\n",query(1,L,R)); } else { temp=nextInt(); update(1,L,R,temp); } } puts(""); } } //******************************************************************** //tle代码 #include <iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #include<ctime> #include<map> #include<queue> #include<vector> using namespace std; const int N=10009; int n,m; int sum[22]; struct Node { int L,R;//区间 int level,exp; int q; }tree[N*5]; int max(int x,int y) { return x>y?x:y; } void create(int t,int L,int R) { tree[t].L=L; tree[t].R=R; tree[t].level=1; tree[t].exp=0; tree[t].q=-1; int mid=(L+R)>>1; if(L<R) { create(t<<1,L,mid); create((t<<1)+1,mid+1,R); } } void down(int t) { if(tree[t].L==tree[t].R)return ; int nl=t<<1,nr=(t<<1)+1; int tmp=tree[t].q; tree[t].q=-1; tree[nl].exp+=tree[nl].level*tmp; if(tree[nl].q==-1) tree[nl].q=tmp; else {down(nl);tree[nl].q=tmp;} while(tree[nl].exp>=sum[tree[nl].level]) tree[nl].level++; tree[nr].exp+=tree[nr].level*tmp; if(tree[nr].q==-1) tree[nr].q=tmp; else {down(nr);tree[nr].q=tmp;} while(tree[nr].exp>=sum[tree[nr].level]) tree[nr].level++; tree[t].exp=max(tree[2*t].exp,tree[2*t+1].exp); tree[t].level=max(tree[2*t].level,tree[2*t+1].level); } int update(int t,int L,int R,int val) { int mid=(tree[t].R+tree[t].L)>>1,tmp; if(tree[t].L==L&&tree[t].R==R) { if(tree[t].q==-1) tree[t].q=val; else { down(t); tree[t].q=val; } tree[t].exp+=tree[t].level*val; while(tree[t].exp>=sum[tree[t].level]) tree[t].level++; return tree[t].exp; } if(tree[t].q!=-1)//向下松弛操作 { down(t); } if(R<=mid)tmp=update(t<<1,L,R,val); else if(L>mid)tmp=update((t<<1)+1,L,R,val); else {tmp=max(update(t<<1,L,mid,val),update((t<<1)+1,mid+1,R,val));} tree[t].exp=max(tmp,tree[t].exp); tree[t].level=max(tree[2*t].level,tree[2*t+1].level); return tree[t].exp; } int query(int t,int L,int R) { int mid=(tree[t].R+tree[t].L)>>1,tmp; if(tree[t].L==L&&tree[t].R==R) { return tree[t].exp; } if(tree[t].q!=-1)//向下松弛操作 { down(t); } if(R<=mid)tmp=query(t<<1,L,R); else if(L>mid)tmp=query((t<<1)+1,L,R); else {tmp=max(query(t<<1,L,mid),query((t<<1)+1,mid+1,R));} return tmp; } int nextInt() { char c; while (c = getchar(), c < '0' || c > '9'); int r = c - '0'; while (c = getchar(), c >= '0' && c <= '9') r = r * 10 + c - '0'; return r; } int main() { int L,R,Case,de,ti,temp; char op[2]; //scanf("%d",&Case); Case=nextInt(); for(int k=1;k<=Case;k++) { //scanf("%d%d%d",&n,&de,&ti); n=nextInt(); de=nextInt(); ti=nextInt(); create(1,1,n); sum[0]=0; for(int i=1;i<de;i++) { //scanf("%d",&sum[i]); //sum[i]=sum[i-1]+temp; sum[i]=nextInt(); } sum[de]=1<<30; printf("Case %d:\n",k); while(ti--) { scanf("%s",op); if(op[0]=='Q') { //scanf("%d%d",&L,&R); //cout<<query(1,L,R)<<endl; L=nextInt(); R=nextInt(); printf("%d\n",query(1,L,R)); } else { //scanf("%d%d%d",&L,&R,&temp); L=nextInt(); R=nextInt(); temp=nextInt(); update(1,L,R,temp); } } printf("\n"); } } //******************************************************************************* //mle代码 #include <iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #include<ctime> #include<map> #include<queue> #include<vector> using namespace std; const int N=10009; int n,m; int sum[12]; struct Node { int L,R;//区间 int level,exp; queue<int> q; }*tree; void create(int t,int L,int R) { tree[t].L=L; tree[t].R=R; tree[t].level=1; tree[t].exp=0; int mid=(L+R)>>1; if(L<R) { create(t<<1,L,mid); create((t<<1)+1,mid+1,R); } } void down(int t)//将t释放至其子树 { if(tree[t].L==tree[t].R)return ; int nl=t<<1,nr=(t<<1)+1; while(!tree[t].q.empty()) { int tmp=tree[t].q.front(); tree[t].q.pop(); tree[nl].exp+=tree[nl].level*tmp; tree[nl].q.push(tmp); while(tree[nl].exp>=sum[tree[nl].level]) tree[nl].level++; tree[nr].exp+=tree[nr].level*tmp; tree[nr].q.push(tmp); while(tree[nr].exp>=sum[tree[nr].level]) tree[nr].level++; } } int update(int t,int L,int R,int val) { int mid=(tree[t].R+tree[t].L)>>1,tmp; if(tree[t].L==L&&tree[t].R==R) { tree[t].q.push(val); tree[t].exp+=tree[t].level*val; while(tree[t].exp>=sum[tree[t].level]) tree[t].level++; return tree[t].exp; } if(!tree[t].q.empty())//向下松弛操作 { down(t); } if(R<=mid)tmp=update(t<<1,L,R,val); else if(L>mid)tmp=update((t<<1)+1,L,R,val); else {tmp=max(update(t<<1,L,mid,val),update((t<<1)+1,mid+1,R,val));} tree[t].exp=max(tmp,tree[t].exp); tree[t].level=max(tree[t].level,max(tree[2*t].level,tree[2*t+1].level)); return tmp; } int query(int t,int L,int R) { int mid=(tree[t].R+tree[t].L)>>1,tmp; if(tree[t].L==L&&tree[t].R==R) { return tree[t].exp; } if(!tree[t].q.empty())//向下松弛操作 { down(t); } if(R<=mid)tmp=query(t<<1,L,R); else if(L>mid)tmp=query((t<<1)+1,L,R); else {tmp=max(query(t<<1,L,mid),query((t<<1)+1,mid+1,R));} return tmp; } int nextInt() { char c; while (c = getchar(), c < '0' || c > '9'); int r = c - '0'; while (c = getchar(), c >= '0' && c <= '9') r = r * 10 + c - '0'; return r; } int main() { int L,R,Case,de,ti,temp; char op[2]; //scanf("%d",&Case); Case=nextInt(); for(int k=1;k<=Case;k++) { //scanf("%d%d%d",&n,&de,&ti); n=nextInt(); de=nextInt(); ti=nextInt(); tree=new Node[4*n]; create(1,1,n); sum[0]=0; for(int i=1;i<de;i++) { sum[i]=nextInt(); } sum[de]=1<<30; printf("Case %d:\n",k); while(ti--) { scanf("%s",op); if(op[0]=='Q') { //scanf("%d%d",&L,&R); //cout<<query(1,L,R)<<endl; L=nextInt(); R=nextInt(); printf("%d\n",query(1,L,R)); } else { //scanf("%d%d%d",&L,&R,&temp); L=nextInt(); R=nextInt(); temp=nextInt(); update(1,L,R,temp); } } printf("\n"); delete tree; } }