【Codeforces Round #254 (Div. 1) C. DZY Loves Colors】线段树

链接:

http://codeforces.com/contest/444/problem/C

题意:

给你n个元素,第i个元素最初的颜色是i,最初每个元素的权值为0,有两种操作,第一种操作是区间赋值x,如果之前元素的颜色为y,那么赋值之后他的权值增加abs(x-y),第二种操作是查询所有元素的权值和。

做法:

首先可以想象如果每次操作区间很大,那么所有元素趋向颜色相同,如果操作区间很小,则可以暴力更新,那么我们可以维护区间颜色是否相同,如果相同则用lazy进行更新,否则再去子区间进行更新,这里要注意lazy对于子区间的更新每次都有一个权值的增加,这个也要用一个lazy数组维护一下。

代码:

#include<stdio.h>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn = 1e5+5;
struct T
{
    int l,r,mid;
    int col,add;
    ll sum,inc;
}tree[maxn<<2];
int col[maxn];
void up(int rt)
{
    if(tree[rt<<1].col==tree[rt<<1|1].col) tree[rt].col=tree[rt<<1].col;
    else tree[rt].col=0;

    tree[rt].sum=tree[rt<<1].sum+tree[rt<<1|1].sum;
}
int maxx=0;
void down(int rt)
{
    if(tree[rt].add!=0)
    {
        int tmp=tree[rt].add;
        tree[rt<<1].col=tmp;
        tree[rt<<1].add=tmp;

        tree[rt<<1|1].col=tmp;
        tree[rt<<1|1].add=tmp;
        tree[rt].add=0;
    }

    if(tree[rt].inc!=0)
    {
        ll tmp=tree[rt].inc;
        tree[rt<<1].sum+=1LL*tmp*(tree[rt<<1].r-tree[rt<<1].l+1);
        tree[rt<<1].inc+=tmp;
        tree[rt<<1|1].sum+=1LL*tmp*(tree[rt<<1|1].r-tree[rt<<1|1].l+1);
        tree[rt<<1|1].inc+=tmp;

        tree[rt].inc=0;
    }

}
void build(int rt,int l,int r)
{
    tree[rt].l=l;
    tree[rt].r=r;
    tree[rt].add=0;
    tree[rt].inc=0;
    if(l==r)
    {
        tree[rt].col=col[l];
        tree[rt].sum=0;
        return ;
    }
    int mid=tree[rt].mid=l+r>>1;
    build(rt<<1,l,mid);
    build(rt<<1|1,mid+1,r);
    up(rt);
    return ;
}
void update(int rt,int l,int r,int co)
{
    if(tree[rt].l>r||tree[rt].r<l) return ;
    if(tree[rt].l>=l&&tree[rt].r<=r&&tree[rt].col!=0)
    {
        tree[rt].sum=tree[rt].sum+1LL*abs(co-tree[rt].col)*(tree[rt].r-tree[rt].l+1);
        tree[rt].inc+=abs(co-tree[rt].col);
        tree[rt].col=co;
        tree[rt].add=co;
        return ;
    }
    down(rt);
    if(tree[rt].mid>=l) update(rt<<1,l,r,co);
    if(tree[rt].mid<r) update(rt<<1|1,l,r,co);
    up(rt);
}
ll query(int rt,int l,int r)
{
    if(tree[rt].l>r||tree[rt].r<l) return 0;
    if(tree[rt].l>=l&&tree[rt].r<=r) return tree[rt].sum;
    down(rt);
    ll ans=0;
    if(tree[rt].mid>=l) ans=ans+query(rt<<1,l,r);
    if(tree[rt].mid<r) ans=ans+query(rt<<1|1,l,r);
    return ans;
}
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) col[i]=i;
    build(1,1,n);
    int cnt=0;
    while(m--)
    {
        int op,x,y,z;
        scanf("%d",&op);
        if(op==1)
        {
            scanf("%d%d%d",&x,&y,&z);
            update(1,x,y,z);
        }
        else
        {
            scanf("%d%d",&x,&y);
            printf("%lld\n",query(1,x,y));
        }
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值