HDU 1698 Just a Hook(線分樹の区間更新『マーク』)

1671 ワード

まず区間1-Nの数はすべて1で、それから区間a-bの値をcに変えさせます;
構想:裸の区間更新.単点更新よりもタグが1つ増えたla[]配列であり、ある区間の数を表すために与えられる必要があるla[]であり、
具体的には、セグメントツリーを作成しながらla[]配列を空にします.区間変更時に変更された量をla[]に割り当て、la[]配列を下に置きます.
この問題に対しては,すべてのla[]の左右の子供を直接la[]の値に変更すればよい.そして左右の子供のsum[]を変えると、左の子供と
sum[rt<<1]=la[rt]*(len-(len/2)、右の子供とsum[rt<<1|1]=la[rt]*(m/2);すなわち、現在の変化量la[]×区間の長さ.最後に、現在のノードのla[]タグを消去します.(PS:線分数の配列の大きさは少なくとも開原葉点数の4倍である.線分樹は実は完全な二叉樹であるからである).
#include
#include
#include
#include
#include
#include
#define LL long long
#define inf 0x3f3f3f3f
#define ls l,mid,rt<<1
#define rs mid+1,r,rt<<1|1
#define M 1000100
using namespace std;
int sum[M*4],n,la[M*4];
void up(int rt)
{
    sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void bu(int l,int r,int rt)
{
    la[rt]=0;
    if(l==r)
    {
        sum[rt]=1;
        return ;
    }
    int mid=(l+r)>>1;
    bu(ls);
    bu(rs);
    up(rt);
}
void down(int rt,int m)
{
    if(la[rt])
    {
        la[rt<<1]=la[rt<<1|1]=la[rt];
        sum[rt<<1]=la[rt]*(m-(m>>1) );
        sum[rt<<1|1]=la[rt]*(m>>1);
        la[rt]=0;
    }
}
void ch(int a,int b,int c,int l,int r,int rt)
{
    if(l>=a&&r<=b)
    {
        la[rt]=c;
        sum[rt]=c*(r-l+1);
        return ;
    }
    down(rt,r-l+1);
    int mid=(l+r)>>1;
    if(a<=mid)
        ch(a,b,c,ls);
    if(mid