HDU4902(线段树)练习题

来源:互联网 发布:sop16 单片机 编辑:程序博客网 时间:2024/05/18 03:58

    如果你还是迷迷糊糊的话,建议先休息一下,前方高能!!!

    题目链接:点这里

    大概意思就是。

    给出一个数列,m次操作,序列长度和操作次数都不超过100000。
    输入:k l r x
    k表示操作类别
    操作分两种:
    (1)把[l,r]区间的数字都变成x。
    (2)把[l,r]区间中比x大的数字变成和x的最大公约数。
    输出
    操作后的数组

    如果你没学过线段树,你可能会用普通的解法,结果是超时(我试过),那么用线段树如何解呢?

    先发着,以后再写吧,不早了。zzz

    /*hdu4902线段树,书上版本妙妙妙呀*/#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;#define mid (r+l>>1)#define lc (d<<1)#define rc (d<<1|1)const int mmax = 100002;struct tree{    int lzx;//lazy懒x表示可替代x    //感觉可以用bool来替代    int v;  //结点值,可替代x}tr[mmax << 2];struct queue{    int k, l, r, x;}que[mmax];int val[mmax];int gcd(int a, int b){    return b == 0 ? a : gcd(b, a%b);}void push(int d)//维护最大的,为了后面优化{    tr[d].v = max(tr[lc].v, tr[rc].v);}void build(int d, int l, int r){    if (l == r)    {        tr[d].v = val[l];        tr[d].lzx = -1;        return;    }    tr[d].lzx = -1;//放上面和build下面一样    build(lc, l, mid);    build(rc, mid + 1, r);    push(d);}void lazy(int d)//懒操作de延伸{    if (tr[d].lzx != -1)    {        tr[lc].lzx = tr[rc].lzx = tr[d].lzx;        tr[lc].v = tr[rc].v = tr[d].v;        tr[d].lzx = -1;//生效完还原    }}void f1(int d, int l, int r, int left, int right, int x){    if (l == left && r == right)    {        tr[d].lzx = x;        tr[d].v = x;        return;    }    lazy(d);    if (left > mid)  f1(rc, mid + 1, r, left, right, x);//区间在右边    else if (right <= mid) f1(lc, l, mid, left, right, x); //等于只能右边加    else    {        f1(rc, mid + 1, r, mid + 1, right, x);//这里要变一下        f1(lc, l, mid, left, mid, x);    }    push(d);}void f2(int d, int l, int r, int left, int right, int x){    if (l == left && r == right)    {        if (tr[d].v <= x) return;        if (tr[d].lzx != -1)        {            tr[d].v = gcd(tr[d].v, x);            tr[d].lzx = tr[d].v;            if (l == r) val[l] = tr[d].lzx;//感觉多余            return;        }        if (l == r)//和模板很像        {            if (val[l] > x) val[l] = gcd(val[l], x);            return;        }        lazy(d);        f2(lc, l, mid, left, mid, x);        f2(rc, mid + 1, r, mid + 1, right, x);        push(d);        return;    }    lazy(d);    if (left > mid)  f2(rc, mid + 1, r, left, right, x);//区间在右边    else if (right <= mid) f2(lc, l, mid, left, right, x); //等于可以加    else    {        f2(rc, mid + 1, r, mid + 1, right, x);        f2(lc, l, mid, left, mid, x);    }    push(d);}void out(int d, int l, int r){    if (tr[d].lzx != -1)    {        for (int i = l; i <= r; i++)        {            printf("%d ", tr[d].lzx);//一样的是d        }        return;    }    if (l == r)    {        printf("%d ", val[l]);        return;    }    lazy(d);    out(lc, l, mid);    out(rc, mid + 1, r);}int main(){    int t;    scanf("%d", &t);    while (t--)    {        //初始化        memset(val, 0, sizeof(val));        //输入        int n1;        scanf("%d", &n1);        for (int i = 1; i <= n1; i++)        {            scanf("%d", &val[i]);        }        build(1, 1, n1);        int n2;        scanf("%d", &n2);        for (int i = 1; i <= n2; i++)        {            scanf("%d%d%d%d", &que[i].k, &que[i].l, &que[i].r, &que[i].x);        }        //处理        for (int i = 1; i <= n2; i++)        {            if (que[i].k == 1)            {                f1(1, 1, n1, que[i].l, que[i].r, que[i].x);            }            else            {                f2(1, 1, n1, que[i].l, que[i].r, que[i].x);            }        /*    out(1, 1, n1);            printf("\n");*/        }        out(1, 1, n1);        printf("\n");    }    return 0;}

    下面是我的代码

    /*hdu4902线段树,自己打的妙妙妙呀*/#include<iostream>#include<cstdio>#include<algorithm>using namespace std;#define lc (d<<1)#define rc (d<<1|1)#define mid (l+r>>1)const int mmax = 100005;int val[mmax];struct tree{    int v;    bool lz;//懒操作标记,lazy简写}tr[mmax << 2];int gcd(int a, int b){    return b == 0 ? a : gcd(b, a%b);}//懒操作void lazy(int d){    if (tr[d].lz)    {        tr[lc].v = tr[rc].v = tr[d].v;        tr[lc].lz = tr[rc].lz = true;        tr[d].lz = false;    }}void push(int d){    tr[d].v = max(tr[lc].v, tr[rc].v);}void build(int d, int l, int r){    if (l == r)    {        tr[d].v = val[l];        tr[d].lz = false;        return;    }    tr[d].lz = false;    build(lc, l, mid);    build(rc, mid + 1, r);    push(d);}void f1(int d, int l, int r, int left, int right, int x){    if (l == left && r == right)    {        tr[d].lz = true;        tr[d].v = x;        return;    }    lazy(d);    if (left > mid) f1(rc, mid+1, r, left, right, x);    else if (right <= mid) f1(lc, l, mid, left, right, x);    else    {        f1(rc, mid+1, r, mid+1, right, x);        f1(lc, l, mid, left, mid, x);    }    push(d);}void f2(int d, int l, int r, int left, int right, int x){    if (l == left && r == right)    {        if (tr[d].v <= x) return;        //lazy说明子结点的tr[d].v是一样的,于是处理父结点就可以了        if (tr[d].lz)        {            tr[d].v = gcd(tr[d].v, x);            return;        }        if (l == r)//没有优化的话,只能一个一个点来处理        {            tr[d].v = gcd(tr[d].v, x);            return;        }        lazy(d);        f2(rc, mid+1, r, mid+1, right, x);        f2(lc, l, mid, left, mid, x);        push(d);        return;    }    lazy(d);    if (left > mid) f2(rc, mid+1, r, left, right, x);    else if (right <= mid) f2(lc, l, mid, left, right, x);    else    {        f2(rc, mid+1, r, mid+1, right, x);        f2(lc, l, mid, left, mid, x);    }    push(d);}void out(int d, int l, int r){    if (tr[d].lz)    {        for (int i = l; i <= r; i++)        {            printf("%d ", tr[d].v);        }        return;    }    if (l == r)    {        printf("%d ", tr[d].v);        return;    }    //    lazy(d);    out(lc, l, mid);    out(rc, mid + 1, r);}int main(){    int t;    scanf("%d", &t);    while (t--)    {        int n1;        scanf("%d", &n1);        for (int i = 1; i <= n1; i++)        {            scanf("%d", &val[i]);        }        build(1, 1, n1);        int n2;        scanf("%d", &n2);        for (int i = 1; i <= n2; i++)        {            int k, l, r, x;            scanf("%d%d%d%d", &k, &l, &r, &x);            if (k == 1)            {                f1(1, 1, n1, l, r, x);            }            else            {                f2(1, 1, n1, l, r, x);            }        }        out(1, 1, n1);        printf("\n");    }    return 0;}