Codeforces Round #250 (Div. 1) D 线段树

看看type = 2的操作,对于区间[l,r]内的元素对x取模,由于取模肯定不能和取模,所以只能每个元素取模,看上去不是区间更新,但是仔细一看,若区间[l,r]内所有的元素都小于x,那么这一区间不需要管,所以还是存在区间整段操作,所以需要lazy,这里也算是一个剪枝了,剩下的就是type = 3的 单点更新,还有type = 1的区间求和,整体操作不难

int n,m;

ll nnum[100000 + 55];

typedef struct Node {
	int l,r;
	ll sum;
	ll maxn;
};

Node tree[100000 * 4 + 55];

void init() {
	memset(nnum,0,sizeof(nnum));
}

bool input() {
	while(cin>>n>>m) {
		for(int i=1;i<=n;i++)scanf("%I64d",&nnum[i]);
		return false;
	}
	return true;
}

void push_up(int id) {
	tree[id].sum = tree[id<<1].sum + tree[id<<1|1].sum;
	tree[id].maxn = max(tree[id<<1].maxn,tree[id<<1|1].maxn);
}

void build(int l,int r,int id) {
	tree[id].l = l;
	tree[id].r = r;
	tree[id].maxn = 0;
	tree[id].sum = 0;
	if(l == r) {
		tree[id].maxn = nnum[l];
		tree[id].sum = nnum[l];
		return ;
	}
	int mid = (l + r)>>1;
	build(l,mid,id<<1);
	build(mid+1,r,id<<1|1);
	push_up(id);
}

ll query(int l,int r,int id) {
	if(tree[id].l == l && tree[id].r == r)return tree[id].sum;
	int mid = (tree[id].l + tree[id].r)>>1;
	if(r <= mid) return query(l,r,id<<1);
	else if(l > mid) return query(l,r,id<<1|1);
	else
		return query(l,mid,id<<1) + query(mid + 1,r,id<<1|1);
}

void update(int l,int r,ll x,int id) {
	if(tree[id].maxn < x) return ;
	int mid = (tree[id].l + tree[id].r)>>1;
	if(tree[id].l == tree[id].r) {
		tree[id].sum %= x;
		tree[id].maxn = tree[id].sum;
		return ;
	}
	if(r <= mid)update(l,r,x,id<<1);
	else if(l > mid)update(l,r,x,id<<1|1);
	else {
		update(l,mid,x,id<<1);
		update(mid + 1,r,x,id<<1|1);
	}
	push_up(id);
}

void update2(int pos,int val,int id) {
	if(tree[id].l == tree[id].r) {
		tree[id].sum = tree[id].maxn = val;
		return ;
	}
	int mid = (tree[id].l + tree[id].r)>>1;
	if(pos <= mid)update2(pos,val,id<<1);
	else update2(pos,val,id<<1|1);
	push_up(id);
}

void cal() {
	build(1,n,1);
	int q = m;
	while(q--) {
		int type;
		scanf("%d",&type);
		if(type == 1) {
			int l,r;
			scanf("%d %d",&l,&r);
			ll ans = query(l,r,1);
			printf("%I64d\n",ans);
		}
		else if(type == 2) {
			int l,r;
			ll x;
			scanf("%d %d %I64d",&l,&r,&x);
			update(l,r,x,1);
		}
		else {
			int k,x;
			scanf("%d %d",&k,&x);
			update2(k,x,1);
		}
	}
}

void output() {

}

int main() {
	while(true) {
		init();
		if(input())return 0;
		cal();
		output();
	}
	return 0;
}
时间: 2024-08-24 12:51:39

Codeforces Round #250 (Div. 1) D 线段树的相关文章

Nastya Hasn&#39;t Written a Legend(Codeforces Round #546 (Div. 2)E+线段树)

题目链接 传送门 题面 题意 给你一个\(a\)数组和一个\(k\)数组,进行\(q\)次操作,操作分为两种: 将\(a_i\)增加\(x\),此时如果\(a_{i+1}<a_i+k_i\),那么就将\(a_{i+1}\)变成\(a_i+k_i\),如果\(a_{i+2}<a_i+k_i\),则将\(a_{i+2}\)变成\(a_{i+1}+k_{i+1}\),以此类推. 查询\(\sum\limits_{i=l}^{r}a_i\). 思路 我们首先存下\(k\)数组的前缀和\(sum1\),

codeforces --- Round #250 (Div. 2) A. The Child and Homework

<传送门> 这题就是一个坑,尼玛wa了一大片啊. 自己被hack了,比赛结束后改了又wa两次才过. [题目大意] 其实就是一个猜题小技巧(联系自己初中考试的时候怎么猜题的,这题就好理解多了).这位同学是这样来选答案的:1.如果有一些选项长度至少比其他所有的描述短两倍,或至少超过所有其他的描述的两倍,那么孩子认为这个选择很可能是正确的.2.如果正好满足以上其中一种条件(重点),这个同学就会选择它,否则就选C.给你一个选择题,让你选择出这个同学将会选择的答案. [题目分析] 首先,这个题目就是一个

Codeforces Round #250 (Div. 1)

这几次CF都挺惨.. A 没条边权设为两端点的最小点权,最后加起来. 数组开小,WA一次 1 #include <iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<stdlib.h> 6 #include<vector> 7 #include<cmath> 8 #include<queue> 9 #

Codeforces Round #250 (Div. 2) C、The Child and Toy

注意此题,每一个部分都有一个能量值v[i],他移除第i部分所需的能量是v[f[1]]+v[f[2]]+...+v[f[k]],其中f[1],f[2],...,f[k]是与i直接相连(且还未被移除)的部分的编号. 注意题目移除的都是与第i部分直接相连的部分的能量值, 将本题目简化得,只考虑两个点1和2,1和2相连,1的能量值是10,2的能量值是20, 移除绳子时,要保持能量最小,可以移除部分2,这样移除的能量就是与2相连的部分1的能量即是10: 故每次相连两部分都移除能量值大的即可 #includ

codeforces --- Round #250 (Div. 2) B. The Child and Set

<传送门> [题目大意] 给你一个sum和一个limit,现在要你在1~limit中找到一些数来使得这些数的和等于sum,如果能找到的话就输出找到的数的个数和这些数,未找到输出"-1". 比赛的时候被hack了. [题目分析] 这题需要将所有的数的lowbit先求出来,然后按照大小排序,然后从后往前判断,如果这个数小于sum那么这个数就是可以构成sum的数,选进去,完了以后判断sum的值是否为0就可以了.做题的时候没将题目理解透彻. #include<bits/std

Codeforces Round #250 (Div. 2)——The Child and Set

题目链接 题意: 给定goal和limit,求1-limit中的若干个数,每一个数最多出现一次,且这些数的lowbit()值之和等于goal,假设存在这种一些数,输出个数和每一个数:否则-1 分析: 先考虑一下比較普通的情况,给一些数,和一个goal,问时候能达到.(最好还是设这些数已经从大到小排序) 考虑能否够贪心,对于当前的数x: 1.之后的数的和能等于x,那么假设x<=goal,显然必须选x: 2.之后的数的和能等于x-1,那么同上(这个情况就是二进制的情况) 3.之后的数的和不包含上述两

Codeforces Round #250 (Div. 1) B 并查集

坑!神坑!深坑!,WA了几十把,最终答案  (ans * 2)/(n * 1.0 * (n - 1)) 要是写成(ans * 2)/(n *(n - 1)*1.0)就是WA,不明白为啥,愤怒的我 全改成double就可以了,若前面变量用了int的 答案必须是前一种写法, 题目不是特别难,没啥思路画一画就有思路了,10^5的n去扫肯定是要超时的,那就想想一次性的10^5,发想通过m是可以的,建边,边权就是两端点中小的那个,然后对最终答案的种数进行分析,发现其实就是 每次你要连接的两块连通块的个数相

Codeforces Round #250 (Div. 1) D. The Child and Sequence 线段树 区间求和+点修改+区间取模

D. The Child and Sequence At the children's day, the child came to Picks's house, and messed his house up. Picks was angry at him. A lot of important things were lost, in particular the favorite sequence of Picks. Fortunately, Picks remembers how to

Codecraft-18 and Codeforces Round #458 C dp D 线段树

Codecraft-18 and Codeforces Round #458 C. Travelling Salesman and Special Numbers 题意: 一个由0.1 组成的数 n,操作:n 有 m 个 1,就把 n 变为 m. 问 <=n 的数中有多少个恰好经过 k 次操作能变为 1. tags:  dp[i][j] 表示长度为 i 且有 j 个 1  的串,比对应的 n 要小的方案数. #include<bits/stdc++.h> using namespace