HDU 4902 Nice boat(数据结构-线段树)

Nice boat

Problem Description

There is an old country and the king fell in love with a devil. The devil always asks the king to do some crazy things. Although the king used to be wise and beloved by his people. Now he is just like a boy in love and can’t refuse any request from the devil.
Also, this devil is looking like a very cute Loli.

Let us continue our story, z*p(actually you) defeat the ‘MengMengDa‘ party‘s leader, and the ‘MengMengDa‘ party dissolved. z*p becomes the most famous guy among the princess‘s knight party.

One day, the people in the party find that z*p has died. As what he has done in the past, people just say ‘Oh, what a nice boat‘ and don‘t care about why he died.

Since then, many people died but no one knows why and everyone is fine about that. Meanwhile, the devil sends her knight to challenge you with Algorithm contest.

There is a hard data structure problem in the contest:

There are n numbers a_1,a_2,...,a_n on a line, everytime you can change every number in a segment [l,r] into a number x(type 1), or change every number a_i in a segment [l,r] which is bigger than x to gcd(a_i,x) (type 2).

You should output the final sequence.

Input

The first line contains an integer T, denoting the number of the test cases.

For each test case, the first line contains a integers n.

The next line contains n integers a_1,a_2,...,a_n separated by a single space.

The next line contains an integer Q, denoting the number of the operations.

The next Q line contains 4 integers t,l,r,x. t denotes the operation type.

T<=2,n,Q<=100000

a_i,x >=0

a_i,x is in the range of int32(C++)

Output

For each test case, output a line with n integers separated by a single space representing the final sequence.

Please output a single more space after end of the sequence

Sample Input

1
10
16807 282475249 1622650073 984943658 1144108930 470211272 101027544 1457850878 1458777923 2007237709
10
1 3 6 74243042
2 4 8 16531729
1 3 4 1474833169
2 1 8 1131570933
2 7 9 1505795335
2 3 7 101929267
1 4 10 1624379149
2 2 8 2110010672
2 6 7 156091745
1 2 5 937186357

Sample Output

16807 937186357 937186357 937186357 937186357 1 1 1624379149 1624379149 1624379149 

Author

WJMZBMR

Source

2014 Multi-University Training Contest 4

Recommend

We have carefully selected several similar problems for you:  4955 4954 4953 4952 4951

题目大意:

给定n个数,m个操作,”1 L R X“ 表示把LR区间的数同时置为X,"2 L R X "表示把LR区间大于X的数比如Y置为gcd(X,Y)。

解题思路:

区间操作,一下子就想到了线段树,但是注意线段树的优化,只要维护记录最大值的maxc,以及bool记录这段是否相等这两个变量即可,详细还请参照我的代码。

解题代码:

#include <iostream>
#include <cstdio>
using namespace std;

const int maxn=110000;
int n,m,d[maxn];

struct tree{
    int l,r,maxc;
    bool flag;
}a[maxn*4];

int gcd(int a,int b){
    return b==0?a:gcd(b,a%b);
}

void push_down(int k){
    if(a[k].flag){
        a[2*k+1].flag=a[2*k].flag=true;
        a[2*k+1].maxc=a[2*k].maxc=a[k].maxc;
    }
}

void push_up(int k){
    a[k].maxc=max(a[2*k].maxc,a[2*k+1].maxc);
    if(a[2*k].flag && a[2*k+1].flag && a[2*k].maxc==a[2*k+1].maxc) a[k].flag=true;
    else a[k].flag=false;
}

void build(int l,int r,int k){
    a[k].l=l;
    a[k].r=r;
    if(l==r){
        a[k].maxc=d[r];
        a[k].flag=true;
    }else{
        int mid=(l+r)/2;
        build(l,mid,2*k);
        build(mid+1,r,2*k+1);
        push_up(k);
    }
}

void insert1(int l,int r,int k,int x){//change data in l~r to x
    if(l<=a[k].l && a[k].r<=r){
        a[k].maxc=x;
        a[k].flag=true;
    }else{
        push_down(k);
        int mid=(a[k].l+a[k].r)/2;
        if(r<=mid) insert1(l,r,2*k,x);
        else if(l>=mid+1) insert1(l,r,2*k+1,x);
        else{
            insert1(l,mid,2*k,x);
            insert1(mid+1,r,2*k+1,x);
        }
        push_up(k);
    }
}

void insert2(int l,int r,int k,int x){//change data >x to gcd(data,x)
    if(l<=a[k].l && a[k].r<=r){
        if(a[k].maxc<=x) return;
        if(a[k].flag){
            a[k].maxc=gcd(a[k].maxc,x);
        }else{
            push_down(k);
            int mid=(a[k].l+a[k].r)/2;
            insert2(l,mid,2*k,x);
            insert2(mid+1,r,2*k+1,x);
            push_up(k);
        }
    }else{
        push_down(k);
        int mid=(a[k].l+a[k].r)/2;
        if(r<=mid) insert2(l,r,2*k,x);
        else if(l>=mid+1) insert2(l,r,2*k+1,x);
        else{
            insert2(l,mid,2*k,x);
            insert2(mid+1,r,2*k+1,x);
        }
        push_up(k);
    }
}

void query(int l,int k){
    if(a[k].l==a[k].r) printf("%d ",a[k].maxc);
    else{
        push_down(k);
        int mid=(a[k].l+a[k].r)/2;
        if(l<=mid) query(l,2*k);
        else query(l,2*k+1);
        push_up(k);
    }
}

void solve(){
    build(0,n-1,1);
    scanf("%d",&m);
    for(int i=0;i<m;i++){
        int op,l,r,x;
        scanf("%d%d%d%d",&op,&l,&r,&x);
        if(op==1) insert1(l-1,r-1,1,x);
        else insert2(l-1,r-1,1,x);
    }
    for(int i=0;i<n;i++){
        query(i,1);
    }
    printf("\n");
}

int main(){
    int T;
    scanf("%d",&T);
    while(T-- >0){
        scanf("%d",&n);
        for(int i=0;i<n;i++) scanf("%d",&d[i]);
        solve();
    }
    return 0;
}

HDU 4902 Nice boat(数据结构-线段树)

时间: 2024-08-04 14:08:58

HDU 4902 Nice boat(数据结构-线段树)的相关文章

HDU 4902 Nice boat(线段树 区间更新)

Nice boat 大意:给你一个区间,每次可以进行两种操作,1:把区间中的数全都变成x  2:把区间中大于x的数变成gcd(a[i], x),最后输出序列. 思路:线段树成段更行,用num数组的叶子存储数据,节点当作lazy来使用. 1 #include <stdio.h> 2 const int maxn = 100005; 3 4 int num[maxn<<2]; 5 6 int gcd(int a, int b){ 7 return b?gcd(b, a%b):a; 8

hdu 4902 Nice boat(线段树区间修改,输出最终序列)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4902 Problem Description There is an old country and the king fell in love with a devil. The devil always asks the king to do some crazy things. Although the king used to be wise and beloved by his peopl

HDU 4902 Nice boat(线段树)

HDU Nice boat 题目链接 题意:给定一个序列,两种操作,把一段变成x,把一段每个数字,如果他大于x,就变成他和x的gcd,求变换完后,最后的序列. 思路:线段树,每个结点多一个cover表示该位置以下区间是否数字全相同,然后每次延迟操作,最后输出的时候单点查询即可 代码: #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int N = 1

HDU 4902 Nice boat 多校4 线段树

给定n个数 第一个操作和普通,区间覆盖性的,把l-r区间的所有值改成固定的val 第二个操作是重点,输入l r x 把l-r区间的所有大于x的数,变成gcd(a[i],x) a[i]即指满足条件的序列上的数值 最后才输出所有值 当时苦思这个地方如何优化,想着不可能单点去更新吧,但是区间gcd,不能保存下来,一来他是要>x才有效,本来聪哥想了一种先把各种x gcd一遍,最后在push下去,发现不行,就是因为他对>x才有效,你在区间就直接gcd了,那不是把不该gcd的也给搞了 还想过说先存起来所有

HDU 4902 Nice boat 成段线段树

操作1 的时候标记deng[rt]表示下面一段数都是与当前节点的值相同 下次操作2时直接对有deng标记的节点gcd更新 (可能还可以更简单) #include <stdio.h> #include <string.h> #include <stdlib.h> #include <limits.h> #include <malloc.h> #include <ctype.h> #include <math.h> #incl

多校第4场 HDU 4902 Nice boat 线段树

思路:这题比赛的时候宝哥说的思路我觉得对的,就是当是2操作的时候,先把数放到数组里,最后查询输出的时候再统一计算,不过那时敲得烂死了,debug了两天,靠-- 上午写的vector在pushDown的时候又忘了clear了,然后MLE了一早上,尼玛,还以为用的数组太大超了,然后又改成结构体,还是MLE,最后把别人的代码交上去发现没MLE,疯了一中午,最后无聊的时候才发现这个错误,尼玛--发现自己调试怎么变得这么弱了呢-- 还有一个需要注意的问题是1与2操作的处理上比较容易出错,这也是我WA了一下

HDU 4902 Nice boat 2014杭电多校训练赛第四场F题(线段树区间更新)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4902 解题报告:输入一个序列,然后有q次操作,操作有两种,第一种是把区间 (l,r) 变成x,第二种是把区间 (l,r) 中大于x的数跟 x 做gcd操作. 线段树区间更新的题目,每个节点保存一个最大和最小值,当该节点的最大值和最小值相等的时候表示这个区间所有的数字都是相同的,可以直接对这个区间进行1或2操作, 进行1操作时,当还没有到达要操作的区间但已经出现了节点的最大值跟最小值相等的情况时,说明

多校训练hdu --Nice boat(线段树,都是泪)

Nice boat Time Limit: 30000/15000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others) Total Submission(s): 47 Accepted Submission(s): 10 Problem Description There is an old country and the king fell in love with a devil. The devil always ask

HDU 1394 Minimum Inversion Number (数据结构-线段树)

Minimum Inversion Number Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 9514    Accepted Submission(s): 5860 Problem Description The inversion number of a given number sequence a1, a2, ..., an