线段树(堆式)[区间更新]

来源:互联网 发布:东莞seo外包 编辑:程序博客网 时间:2024/05/20 08:22

区间更新是个坎。。。 堆式的区间更新是个大坎。。。

hdu1698 Just a Hook

解法1 还没理解自底向上的更新方法, 还是自顶向下的递归更新, 跑了859ms,悲剧。。。

代码很丑, 不过自创了一个debug函数,可以看树的结构, 不错,不错。

#include <cstdio>#include <string.h>#include <algorithm>using namespace std;typedef long long ll;const int maxn=100000+123;int T[maxn*3];int M, h;int bit(int x)/// get highest 1 in bit-number{    if(x==0)return 0;    int n=31;    if((x>>16)==0){n-=16; x<<=16;}    if((x>>24)==0){n-=8; x<<=8;}    if((x>>28)==0){n-=4; x<<=4;}    if((x>>30)==0){n-=2; x<<=2;}    return n-(x>>31);}inline void merge (const int &x)//合并2个儿子的信息{    if(T[x]==0 && T[x<<1]==T[x<<1|1])T[x]=T[x<<1];}void init(const int & x){    h=bit(x);    M=1<<h;    memset (T, 0, sizeof(T));    for (int i=M; i<x+M; ++i)        T[i]=1;    for (int i=M-1; i>0; --i)        merge(i);}void Updata(int x, int v){    T[x]=v;    if(x<M)    {        T[x<<1]=v;        T[x<<1|1]=v;    }}void color (int l, int r, int x, int root){    if(T[root]==x)return ;    if(root>M+M)return;    if(root>=M){if(root>l && root<r)T[root]=x; return;}    int t=h-bit(root)+1;    if((l>>t)<root && (r>>t)>root)        T[root]=x;    else    {        if(T[root]){T[root<<1]=T[root]; T[root<<1|1]=T[root]; T[root]=0;}        if((l>>(t-1))<=(root<<1))color(l, r, x, root<<1);        if((r>>(t-1))>=(root<<1|1))color(l, r, x, root<<1|1);    }}inline void Change(int l, int r, int x){    color (l+M-1, r+M+1, x, 1);}int getson (int x){    if(x>=M)return T[x];    if(T[x])    {        int t=h-bit(x)+1;        return (1<<t)*T[x];    }    return getson(x<<1)+getson(x<<1|1);}int Request (int l, int r){    return getson(1);}void debug(int n){    for (int i=1; i<M+n; ++i)        printf("%d%c", T[i], ((i^1)&&(i^3)&&(i^7)&&(i^15)&&(i^31)&&(i^63))?' ':'\n');    puts("");}int main (){    int cas;    scanf("%d", &cas);    for (int I=1; I<=cas; ++I)    {        int n, k;        scanf("%d", &n);        init(n);        scanf("%d", &k);        while (k--)        {            int s, t, v;            scanf("%d%d%d", &s, &t, &v);            Change(s-1, t-1, v);            //debug(n);        }        printf("Case %d: The total value of the hook is %d.\n", I, Request(0, n-1));    }    return 0;}



poj2528 Mayor’s posters


题意:在墙上贴海报,海报可以互相覆盖,问最后可以看见几张海报


这个区间的离散化很重要


#include <cstdio>#include <string.h>#include <algorithm>using namespace std;typedef long long ll;const int maxn=100000+123;int T[maxn*3];int M, h;int bit(int x)/// get highest 1 in bit-number{    if(x==0)return 0;    int n=31;    if((x>>16)==0){n-=16; x<<=16;}    if((x>>24)==0){n-=8; x<<=8;}    if((x>>28)==0){n-=4; x<<=4;}    if((x>>30)==0){n-=2; x<<=2;}    return n-(x>>31);}void init(int x){    h=bit(x);    M=1<<h;    memset (T, 0, sizeof(T));}inline void Updata(const int & x, const int & v){    T[x]=v;}void Down (int l, int r)// 区间下传信息, 实际上只是对2个开区间边界下传信息{    for (int i=h; i>0; --i)    {        int ll=l>>i, rr=r>>i;        if(T[ll])        {            T[ll<<1]=T[ll<<1|1]=T[ll];        }        if(T[rr])        {            T[rr<<1]=T[rr<<1|1]=T[rr];        }        T[ll]=T[rr]=0;    }}void Interval_Updata(int l, int r, int x){    int t=1;    for (l+=M-1, r+=M+1, Down(l, r); l^r^1; l>>=1, r>>=1, t<<=1)    {        if(~l&1) Updata(l^1, x);        if( r&1) Updata(r^1, x);    }}void debug(int n){    for (int i=1; i<M+n; ++i)        printf("%d%c", T[i], ((i^1)&&(i^3)&&(i^7)&&(i^15)&&(i^31)&&(i^63))?' ':'\n');    puts("");}bool flag[maxn];int ans;void Request (int x){    if(T[x])    {        if(flag[T[x]])return;        ans++; flag[T[x]]=true;        return;    }    if(x<M)    {        Request(x<<1);        Request(x<<1|1);    }}int l[maxn], r[maxn];int X[maxn];int cnt;int bin(int x){    int low=0, high=cnt, mid;    while (low<=high)    {        mid=(low+high)>>1;        //printf("%d %d %d %d  %d\n", low, high, mid, X[mid], x);        if(X[mid]==x)return mid;        if(X[mid]<x)low=mid+1;        if(X[mid]>x)high=mid-1;    }}int main (){    int cas, n;    scanf("%d", &cas);    while (cas--)    {        scanf("%d", &n);        int cnt1=0, cnt2=1;        for (int i=0; i<n; ++i)        {            scanf("%d%d", l+i, r+i);            X[cnt1++]=l[i];            X[cnt1++]=r[i];        }        sort(X, X+cnt1);        for (int i=1; i<cnt1; ++i)//去重            if(X[i]!=X[i-1])X[cnt2++]=X[i];        cnt1=cnt2;        for (int i=1; i<cnt1; ++i)        //加间隔,因为这里的节点表示的是区间,离散量之间没有一个中点会出现        //1-10 1-4 5-10和1-10 1-4 6-10答案都是2的情况,但实际上第二个答案是3            if(X[i]>X[i-1]+1)X[cnt2++]=X[i-1]+1;        sort(X, X+cnt2);        cnt=cnt2;        init(cnt);        //debug(n);        for (int i=0; i<n; ++i)        {            int ll=bin(l[i]), rr=bin(r[i]);            Interval_Updata(ll, rr, i+1);            //printf("l=%d r=%d  %d  %d\n", ll, rr, l[i], r[i]);            //debug(cnt);        }        memset (flag, 0, sizeof(flag));        ans=0;        Request(1);        printf("%d\n", ans);    }    return 0;}


http://poj.org/problem?id=3468

区间加减, 区间求和

#include <cstdio>#include <string.h>#include <algorithm>using namespace std;typedef long long ll;const int maxn=100000+123;ll T[maxn*3];ll flag[maxn*3];int M, h;int bit(int x)/// get highest 1 in bit-number{    if(x==0)return 0;    int n=31;    if((x>>16)==0){n-=16; x<<=16;}    if((x>>24)==0){n-=8; x<<=8;}    if((x>>28)==0){n-=4; x<<=4;}    if((x>>30)==0){n-=2; x<<=2;}    return n-(x>>31);}void merge (const int &x)// 合并子节点的信息到父亲{    T[x]=T[x<<1]+T[x<<1|1];}void init(const int &x){    h=bit(x);    M=1<<h;    memset (T, 0, sizeof(T));    memset (flag, 0, sizeof(flag));    for (int i=0; i<x; ++i)        scanf("%lld", T+i+M);    for (int i=M-1; i>0; --i)        merge(i);}void Down(const int &k)// 下传标记并对当前标记清除{    for (int i=h; i>0; --i)    {        int p=k>>i;        flag[p<<1]+=flag[p]; flag[p<<1|1]+=flag[p];        T[p<<1]+=flag[p]*(1ll<<i-1); T[p<<1|1]+=flag[p]*(1ll<<i-1);        flag[p]=0;    }}void Updata(int x, int v, int w)//更新节点{    flag[x]+=v;    T[x]+=(ll)v*(ll)w;}void Interval_Updata(int l, int r, int v)//区间更新, 先下传, 再更新 再合并{    int t=1;    for (l+=M-1, r+=M+1, Down(l), Down(r); l^r^1; r>>=1, l>>=1, merge(r), merge(l), t<<=1)    {        if(~l&1) Updata(l^1, v, t);        if( r&1) Updata(r^1, v, t);    }    while (l>1)    {        l>>=1; r>>=1;        merge(l);        if(l^r)merge(r);    }}ll Request (int l, int r)// 区间查询, 先下传, 再查询{    ll res=0;    for (l+=M-1, r+=M+1, Down(l), Down(r); l^r^1; l>>=1, r>>=1)    {        if(~l&1)res+=T[l^1];        if( r&1)res+=T[r^1];    }    return res;}void debug(int n)//你懂的{    for (int i=1; i<M+n; ++i)        printf("%lld%c", T[i], ((i^1)&&(i^3)&&(i^7)&&(i^15)&&(i^31)&&(i^63))?' ':'\n');    puts("");}int main (){    char op[5];    int n, q, s, t, w;    while (~scanf("%d%d", &n, &q))    {        init(n);        while(q--)        {            scanf("%s", op);            if(op[0]=='Q')            {                scanf("%d%d", &s, &t);                printf("%lld\n", Request(s-1, t-1));            }            if(op[0]=='C')            {                scanf("%d%d%d", &s, &t, &w);                Interval_Updata(s-1, t-1, w);            }        }    }    return 0;}/*10 101 2 3 4 5 6 7 8 9 10C 1 4 1000000000Q 1 10Q 2 4C 3 6 3Q 2 4Q 1 10C 1 10 2Q 1 10C 1 10 -2Q 1 10*/