
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