您的位置:首页 > 其它

Codeforces Round #179 (Div. 2) C Greg and Array 两个线段树

2015-07-25 21:14 218 查看
纯线段树的模板,只是要注意在计算加多少次的时候也当作线段树来做,注意longlong,为了保险我把所有int都改成了longlong
AC代码
#include<cstdio>
#include<iostream>
#include<cstring>
#define maxn 100010
#define ls l,m,nod<<1
#define rs m+1,r,nod<<1|1
using namespace std;
struct oper{
long long l;
long long r;
long long val;
}op[maxn];
long long sum[maxn<<2],src[maxn];
long long flag[maxn<<2],n,q,m;
void pushup(long long nod){          //此题不用,可有可无
sum[nod]=sum[nod<<1]+sum[nod<<1|1];
}
void pushdown(long long nod,long long m){
if(flag[nod])
{
flag[nod<<1]+=flag[nod];
flag[nod<<1|1]+=flag[nod];
sum[nod<<1]+=(long long)(m-(m>>1))*flag[nod];
sum[nod<<1|1]+=(long long)(m>>1)*flag[nod];
flag[nod]=0;
}
}
void build(long long l,long long r,long long nod)
{
flag[nod]=0;
if(l==r)
{
//cout<<nod;
sum[nod] = 0;
return;
}
long long m = (l+r)>>1;
build(ls);
build(rs);
pushup(nod);
}
void update(long long ll,long long rr,long long val,long long l,long long r,long long nod)
{
if(l>=ll&&r<=rr)
{
flag[nod]+=val;
sum[nod]+=(long long)(r-l+1)*val;
return;
}
pushdown(nod,r-l+1);
long long m=(l+r)>>1;
if(ll<=m)
update(ll,rr,val,ls);
if(rr>m)
update(ll,rr,val,rs);
pushup(nod);
}
long long query(long long ql,long long qr,long long l,long long r,long long nod){
long long summ=0,ta=0,tb=0;
if(l>=ql&&r<=qr)
{summ+=sum[nod];
return summ;}
pushdown(nod,r-l+1);
long long m=(l+r)>>1;
if(ql<=m)
ta=query(ql,qr,ls);
if(qr>m)
tb=query(ql,qr,rs);
summ+=ta;
summ+=tb;
return summ;
}
int main(){
memset(sum,0,sizeof(sum));
scanf("%lld%lld%lld",&n,&m,&q);
for(int i = 1; i <= n; i++)
scanf("%lld",&src[i]);
for(int i = 1; i <= m; i++)
scanf("%lld%lld%lld",&op[i].l,&op[i].r,&op[i].val);
build(1,m,1);
long long a,b,v;

/*for(int i = 0; i < 40; i++)
cout<<sum[i]<<"  ";*/
while(q--)
{
scanf("%lld%lld",&a,&b);
update(a,b,1,1,m,1);
}
for(int i = 1; i <= m; i++)
op[i].val*=query(i,i,1,m,1);
memset(sum,0,sizeof(sum));
build(1,n,1);
for(int i = 1; i <= m; i++)
update(op[i].l,op[i].r,op[i].val,1,n,1);
printf("%lld",query(1,1,1,n,1) + src[1]);
for(int i = 2; i <= n; i++)
printf(" %lld",query(i,i,1,n,1) + src[i]);
printf("\n");
}


后更:今天突然知道了一个非常屌的写法,用数组记录加减次数,加入数组为f,如果从i位置到j位置都加的话,就让f[i]++,f[j+1]--,最后再从1到n,f[i] += f[i-1],然后就能处理出来每次操作进行多少次了,同理,对上面值得修改也可以如此,附代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#define maxn 100010
using namespace std;
long long a[maxn],d[maxn],g[maxn];
int n,m,k,x,y,l[maxn],r[maxn],f[maxn];
int main(){
cin>>m>>n>>k;
for(int i = 1; i <= m; i++)
scanf("%lld",a+i);
for(int i = 1; i <= n; i++)
scanf("%d%d%lld",l+i,r+i,d+i);

for(int i = 1; i <= k; i++)
scanf("%d%d",&x,&y),f[x]++,f[y+1]--;   //与下一步结合起来做,代表从x到y这个区间内所有的值都加了一
for(int i = 1; i <= n; i++)
f[i] += f[i-1];

for(int i = 1; i <= n; i++)
g[l[i]]+=d[i]*f[i],g[r[i] + 1]-=d[i]*f[i];   //同上
for(int i = 1; i <= m; i++)
g[i]+=g[i-1];

for(int i = 1; i <= m; i++)
printf("%lld ",g[i] + a[i]);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: