[codeforces803G]Periodic RMQ Problem

time limit per test : 4 seconds
memory limit per test : 512 megabytes

You are given an array a a a consisting of positive integers and q q q queries to this array. There are two types of queries:

1 1 1 l l l r r r x x x — for each index i such that l   ≤   i   ≤   r l ≤ i ≤ r lir set a i   =   x a_i = x ai=x.
2 2 2 l l l r r r — find the minimum among such a i a_i ai that l   ≤   i   ≤   r l ≤ i ≤ r lir.

We decided that this problem is too easy. So the array a is given in a compressed form: there is an array b b b consisting of n n n elements and a number k k k in the input, and before all queries a a a is equal to the concatenation of k k k arrays b b b (so the size of a is n ⋅ k n·k nk).
Input

The first line contains two integers n n n and k k k ( 1   ≤   n   ≤   1 0 5 1 ≤ n ≤ 10^5 1n105, 1   ≤   k   ≤   1 0 4 1 ≤ k ≤ 10^4 1k104).
The second line contains n n n integers — elements of the array b ( 1   ≤   b i   ≤   1 0 9 ) b (1 ≤ b_i ≤ 10^9) b(1bi109).
The third line contains one integer q ( 1   ≤   q   ≤   1 0 5 ) q (1 ≤ q ≤ 10^5) q(1q105).

Then q q q lines follow, each representing a query. Each query is given either as 1 1 1 l l l r r r x x x — set all elements in the segment from l l l till r r r (including borders) to x ( 1   ≤   l   ≤   r   ≤   n ⋅ k , 1   ≤   x   ≤   1 0 9 ) x (1 ≤ l ≤ r ≤ n·k, 1 ≤ x ≤ 10^9) x(1lrnk,1x109) or as 2 2 2 l l l r r r — find the minimum among all elements in the segment from l l l till r r r ( 1   ≤   l   ≤   r   ≤   n ⋅ k ) (1 ≤ l ≤ r ≤ n·k) (1lrnk).
Output

For each query of type 2 2 2 print the answer to this query — the minimum on the corresponding segment.

Examples

Input

3 1
1 2 3
3
2 1 3
1 1 2 4
2 1 3

Output

1
3

Input

3 2
1 2 3
5
2 4 4
1 4 4 5
2 4 4
1 1 6 1
2 6 6

Output

1
5
1

题意:
给一个长度为 n ( n &lt; = 1 0 5 ) n(n&lt;=10^5) n(n<=105)的序列 a a a,然后将其复制 k ( k &lt; = 1 0 4 ) k(k&lt;=10^4) k(k<=104)份,形成一个新的序列 b b b
然后对 b b b序列,有 q q q次操作。
操作有两种,一种是区间覆盖,另一种是求区间最小值。

题解:
动态开点线段树裸题。因为每次操作最多新增 l o g ( n ∗ k ) log(n*k) log(nk)个节点。

然后对于一个新节点的最小值,如果区间长度大于等于 n n n那么其最小值就跟原数组 a a a一样,其他的区间你可以对原数组 a a a开一个线段树来解决。

#include<bits/stdc++.h>
#define LiangJiaJun main
#define INF 1999122700
using namespace std;
int mint;
struct tree{
    int l,r;
    int ls,rs;
    int w,tag;
    tree(){}
    tree(int L,int R,int LS,int RS,int W,int TAG){
        l=L;r=R;ls=LS;rs=RS;w=W;tag=TAG;
    }
}tr[5000004];
int a[100004];
int n,k,cnt;
int up,td[400004];
int pask(int l,int r){
    int ans=INF;
    for(l=l+up-1,r=r+up+1;r-l>1;r>>=1,l>>=1){
        if(~l&1)ans=min(ans,td[l+1]);
        if(r&1)ans=min(ans,td[r-1]);
    }
    return ans;
}
int ask(int l,int r){
    if(r-l+1>=n)return mint;
    l--;l%=n;l++;
    r--;r%=n;r++;
    if(l<=r)return pask(l,r);
    else return min(pask(l,n),pask(1,r));
}

void takedown(int k){
     int l=tr[k].l,r=tr[k].r;
     int mid=(l+r)>>1;
     if(tr[k].ls==-1){
        tr[k].ls=++cnt;
        tr[cnt]=tree(l,mid,-1,-1,ask(l,mid),-1);
     }
     if(tr[k].rs==-1){
        tr[k].rs=++cnt;
        tr[cnt]=tree(mid+1,r,-1,-1,ask(mid+1,r),-1);
     }
}

void push(int k){
     takedown(k);
     if(tr[k].tag==-1)return ;
     int tag=tr[k].tag;
     tr[k].tag=-1;
     tr[tr[k].ls].w=tag;
     tr[tr[k].ls].tag=tag;
     tr[tr[k].rs].w=tag;
     tr[tr[k].rs].tag=tag;
}

void change(int k,int a,int b,int x){
     int l=tr[k].l,r=tr[k].r;
     if(l==a&&r==b){
        tr[k].tag=x;
        tr[k].w=x;
        return ;
     }
     push(k);
     int mid=(l+r)>>1;
     if(b<=mid)change(tr[k].ls,a,b,x);
     else if(a>mid)change(tr[k].rs,a,b,x);
     else{
        change(tr[k].ls,a,mid,x);
        change(tr[k].rs,mid+1,b,x);
     }
     tr[k].w=min(tr[tr[k].ls].w,tr[tr[k].rs].w);
}

int query(int k,int a,int b){
    int l=tr[k].l,r=tr[k].r;
    if(l==a&&r==b)return tr[k].w;
    push(k);
    int mid=(l+r)>>1;
    if(b<=mid)return query(tr[k].ls,a,b);
    else if(a>mid)return query(tr[k].rs,a,b);
    else return min(query(tr[k].ls,a,mid),query(tr[k].rs,mid+1,b));
}
int LiangJiaJun(){
    cnt=0;
    up=1;
    scanf("%d%d",&n,&k);
    mint=-1;
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        if(mint==-1)mint=a[i];
        mint=min(mint,a[i]);
    }

    while(up<n+2)up<<=1;
    for(int i=1;i<=n;i++)td[i+up]=a[i];
    for(int i=up;i>=1;i--)td[i]=min(td[i<<1],td[i<<1|1]);

    tr[++cnt]=tree(1,n*k,-1,-1,mint,-1);
    int q;scanf("%d",&q);
    while(q--){
        int t,l,r,x;
        scanf("%d%d%d",&t,&l,&r);
        if(t==1){
            scanf("%d",&x);
            change(1,l,r,x);
        }
        if(t==2){
            printf("%d\n",query(1,l,r));
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值