Acwing 3729. 改变数组元素(差分) java

👵 改变数组元素
在这里插入图片描述

🧐 神之区间维护版

import java.util.*;


class Main{
    static int T,n; 
    static int N = (int)2e5+10;
    static int[] a = new int[N];
    
    
    public static void main(String[] ars){
        Scanner sc = new Scanner(System.in);
        T = sc.nextInt();
        while((T--)!=0)
        {
            n = sc.nextInt();
            for(int i = 1; i <= n; i++){
                a[i] = sc.nextInt();
            }
            int l = N;
            for(int i = n; i >= 1; i--)
            {
                l = Math.min(l,i-a[i]+1);//更新边界
                if(l <= i) a[i] = 1;//在区间内就更新元素
            }             
            for(int i =1; i <= n; i++)
                System.out.print(a[i] + " ");              
            System.out.println();         
        }      
    }           
}

👵 差分数组版
👍 大佬详解版

import java.util.*;


class Main{
   	static int N = (int) 2e5 + 10;

	static int n;
	static int[] b = new int[N];// 差分数组

	public static void main(String[] args)
	{
		Scanner sc = new Scanner(System.in);
		int T = sc.nextInt();
		while (T-- != 0)
		{
			n = sc.nextInt();
			Arrays.fill(b,0);
			for (int i = 1; i <= n; i++)
			{
				int a = sc.nextInt();
				int l = Math.max(1, i - a + 1);// 区间左端点,max函数防止越界
				int r = i;// 区间右端点
//				差分本差:
//				左端点 +1,右端点 -1,相当于区间内的前缀和都 +1 
//				此场景种,把输入的数据当成前缀和的数 ,数组存的是差分后的 每个元素
				b[l]++;
				b[r + 1]--;
			}
			
			for(int i = 1; i <= n; i++)
			{
				b[i] += b[i-1];//现在 b存的又是前缀和了
				int k = b[i]!=0?1:0;//只要b[i]不为0,就是经过了0转1的情况
				System.out.print(k+" ");
			}
			System.out.println();
		}
	}
}

👵 区间合并版
👵 参考连接

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
typedef pair<int,int> PII;
const int N=200010;
PII range[N]; // 存储更新区间
int a[N]; // 存储答案数组
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        int n,cnt=0; // cnt表示区间个数
        cin>>n;
        memset(a,0,(n+1)*4); // 清空答案数组前n+1个数
        for(int i=1;i<=n;i++) 
        {
            int x;
            cin>>x;
            if(x>0) // 如果需要更改区间
            {
                int l=max(1,i-x+1),r=i;
                range[cnt++]={l,r}; 
            }
        }

        sort(range,range+cnt); // 排序
        int st=0,ed=0; // 维护区间左右端点
        for(int i=0;i<cnt;i++) // 区间合并模板
        {
            if(range[i].first>ed) // 新维护区间
            {
                for(int j=st;j<=ed;j++) a[j]=1; // 将维护区间变为1
                st=range[i].first,ed=range[i].second; // 新维护区间
            }
            else ed=max(range[i].second,ed); // 更新维护区间
        }
        for(int j=st;j<=ed;j++) a[j]=1; // 将最后一个维护区间变为1
        for(int i=1;i<=n;i++) cout<<a[i]<<' '; // 输出答案数组
        cout<<endl;
    }
    return 0;
}

😋 常数优化

① 标记流优化了 0.2 秒
② 数组按需初始化优化了 0.2 秒

	static int N = (int) 2e5 + 10;

	static int n;
	static int[] b = new int[N];// 差分数组

	public static void main(String[] args) throws IOException
	{
// 		Scanner sc = new Scanner(System.in);
//		标记流输入,快 0.2 秒左右
		StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
		in.nextToken();
		int T = (int) in.nval;
// 		int T = sc.nextInt();
		while (T-- != 0)
		{
// 			n = sc.nextInt();
			in.nextToken();
			n = (int) in.nval;
//			Arrays.fill(b, 0);

//			由于不是每组数据都会用到 数组的所有空间,所以初始化需要用的空间即可 
			for (int i = 0; i <= n + 1; i++)
			{
				b[i] = 0;
			}
			for (int i = 1; i <= n; i++)
			{
				// int a = sc.nextInt();
				in.nextToken();
				int a = (int) in.nval;
				int l = Math.max(1, i - a + 1);// 区间左端点,max函数防止越界
				int r = i;// 区间右端点
//				差分本差:
//				左端点 +1,右端点 -1,相当于区间内的前缀和都 +1 【关键:前缀和才是 结果】
//				此场景种,把输入的数据当成前缀和的数 ,数组存的是差分后的 每个元素
				b[l]++;
				b[r + 1]--;
			}

			for (int i = 1; i <= n; i++)
			{
				b[i] += b[i - 1];// 现在 b存的又是前缀和了
				int k = b[i] != 0 ? 1 : 0;
				System.out.print(k + " ");
			}
			System.out.println();
		}
	}

在这里插入图片描述
👨‍🏫 Arrays.fill (数组,初始下标,末尾下标(排除),初始化的值);

posted @ 2023-02-14 17:07  兑生  阅读(22)  评论(0)    收藏  举报  来源
Live2D