标签:
1 10 5 1 1 10 2 3 10 3 5 10 4 7 10 5 9 10
30
/* 线段树 结论:只要是set的,就是直接赋值的;只要是add的,就是在原基础上加的;set时把add置0 还有就是时刻更新sum值,使其保持正确. */ #include <stdio.h> #include <string.h> #include <algorithm> using namespace std; typedef long long ll; const int maxn=100000+10; ll sum[maxn*4],add[maxn*4],set[maxn*4]; void pushUp(int k){ sum[k]=sum[k*2]+sum[k*2+1]; } void pushDown(int k,int l,int r){ int lc=k*2,rc=k*2+1,m=(l+r)/2; if(set[k]!=-1){ add[lc]=add[rc]=0; //这里被赋值,那么子树的add就没用了 set[lc]=set[rc]=set[k]; sum[lc]=set[k]*(m-l+1); //这里的sum就是直接赋值,因为之前的值不复存在,而是用现在的新的set值计算 sum[rc]=set[k]*(r-m); set[k]=-1; } if(add[k]){ add[lc]+=add[k];add[rc]+=add[k]; sum[lc]+=add[k]*(m-l+1); //处理add时,sum就不能直接赋值,而是在原来的基础上加 sum[rc]+=add[k]*(r-m); add[k]=0; } } void Set(int a,int b,ll v,int k,int l,int r){ if(a<=l && r<=b){ set[k]=v;add[k]=0;sum[k]=v*(r-l+1);return ; //注意这里有add[k]=0!!!!!!!!!!!!!!!!!! } pushDown(k,l,r); int m=(l+r)/2; if(a<=m) Set(a,b,v,k*2,l,m); if(b>m) Set(a,b,v,k*2+1,m+1,r); pushUp(k); } void Add(int a,int b,ll v,int k,int l,int r){ if(a<=l && r<=b){ add[k]+=v;sum[k]+=v*(r-l+1);return ; } pushDown(k,l,r); int m=(l+r)/2; if(a<=m) Add(a,b,v,k*2,l,m); if(b>m) Add(a,b,v,k*2+1,m+1,r); pushUp(k); } ll ask(int a,int b,int k,int l,int r){ if(a<=l && r<=b){ return sum[k]; } pushDown(k,l,r); int m=(l+r)/2; ll res=0; if(a<=m) res+=ask(a,b,k*2,l,m); if(b>m) res+=ask(a,b,k*2+1,m+1,r); pushUp(k); return res; } int main() { int i,T,n,m,a,b,t; scanf("%d",&T); while(T--){ scanf("%d%d",&n,&m); memset(add,0,sizeof(add)); Set(1,n,(ll)0,1,1,n); //set[1]=0是不对的。。。。。 ll res=0; t=0; while(m--){ int t1; scanf("%d%d%d",&t1,&a,&b); Add(1,n,(ll)t1-t,1,1,n); res+=ask(a,b,1,1,n); Set(a,b,(ll)0,1,1,n); t=t1; } printf("%lld\n",res); } return 0; }
版权声明:本文为博主原创文章,未经博主允许不得转载。
SDUT2880 Devour Magic 线段树(set+add标记)
标签:
原文地址:http://blog.csdn.net/u013068502/article/details/47253103