CodeForces 482B 有趣的数列 数据结构+线段树+位运算的技巧

CodeForces 482B 有趣的数列

Time Limit:1000MS    Memory Limit:262144KB    64bit IO Format:%I64d & %I64u

Description

        给你一个非负整数组成的数列a [1], a[2], ..., a[n] ,如果它满足m个约束,我们就称它为有趣数列。每个约束包含3个整数 li, ri, qi ( 1 ≤ li ≤ ri ≤ n) 表示 等于 qi.

        请找出这样的一个序列。

Input

第一行两个整数n, m (1 ≤ n ≤ 105, 1 ≤ m ≤ 105) —数列长度和约束个数.

接下来m行 li, ri, qi (1 ≤ li ≤ ri ≤ n, 0 ≤ qi < 230) 表示第i个约束.

Output

如果存在这样一个数列,输出 "YES" (没有括号) 第二行输出a[1], a[2], ..., a[n] (0 ≤ a[i] < 230) . 如果有多解,请输出任意一组。

如果无解输出 "NO"(没有括号).

Sample Input

  

3 1

1 3 3

3 2

1 3 3

1 3 2

Sample Output

 

YES

3 3 3

NO


解题思路:

题目描述的很清楚了

1,首先这题给了一堆的约束,然后让你给任意一组正确的答案,那么就是按照约束构造数组咯

2,然后每个约束是指一个区间内的数&起来的等于一个指定的值q

3,然后分析分析一下就可以发现,每一个约束都让这个区间内的数可以等于q

4,那就是让个区间内的数都或q(初始这个数组是0的,或运算可以让二进制的1保留下来)

5,所有的约束都执行完之后,最后再检测一遍,是不是形成的数组可以满足每一个约束

6,可以的话就输出这个数组,ok了


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

#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
const int maxn = 100005;
int n,m;
int col[maxn<<2];
int sum[maxn<<2];
int we ;
int getss(){
    we = 0 ;
    for(int i=1;i<=31;i++){
        we<<=1;
        we|=1 ;
    }
}
void PushUp(int rt) {
	sum[rt] = sum[rt<<1] & sum[rt<<1|1];
}
void PushDown(int rt) {
	if (col[rt]) {
            //printf("rt = %d\n",col[rt]);
		col[rt<<1] |=col[rt];
        col[rt<<1|1] |= col[rt];
		sum[rt<<1] |= col[rt];
		sum[rt<<1|1] |= col[rt];
		col[rt] = 0;
	}
}
void update(int L,int R,int c,int l,int r,int rt) {
	if (L <= l && r <= R) {
		col[rt] = col[rt]|c;
		sum[rt] = sum[rt]|c;
		return ;
	}
	PushDown(rt);
	int m = (l + r) >> 1;
	if (L <= m) update(L , R , c , lson);
	if (R > m) update(L , R , c , rson);
	PushUp(rt);
}
int query(int L,int R,int l,int r,int rt) {
	if (L <= l && r <= R) {
		//if(l==r)printf("rt = %d\n",sum[rt]);
		return sum[rt];

	}
	PushDown(rt);
	int m = (l + r) >> 1;
	int ret = we;
	//printf("%d\n",we);
	if (L <= m) ret =ret&query(L , R , lson);
	//printf("ret1 = %d\n",ret);
	if (m < R) ret = ret&query(L , R , rson);
	//printf("ret2 = %d\n",ret);
    //PushUp(rt);
	return ret;
}
int a[maxn];
int b[maxn];
int c[maxn] ;
int main() {
    getss() ;
    //freopen("in.txt","r",stdin);
    //printf("%d\n",1<<30);
	while(~scanf("%d%d",&n,&m)){
        memset(col,0,sizeof(col)) ;
        memset(sum,0,sizeof(sum)) ;
        for(int i=0;i<m;i++){
            //int a,b,c ;
            scanf("%d%d%d",&a[i],&b[i],&c[i]) ;
            update(a[i],b[i],c[i],1,n,1) ;
        }

        //for(int i=1;i<=n;i++)query(i,i,1,n,1);


        bool flag = true ;
        for(int i=0;i<m;i++){
            //printf("q = %d\n",query(a[i],b[i],1,n,1));
            if(c[i]!=query(a[i],b[i],1,n,1)){
                flag = false ;
                break ;
            }
        }
        if(flag){
            printf("YES\n");
            for(int i=1;i<n;i++){
                printf("%d ",query(i,i,1,n,1)) ;
            }printf("%d\n",query(n,n,1,n,1));
        }else{
            printf("NO\n");
        }

	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值