首页 > 其他分享 >P3071 [USACO13JAN] Seating G 题解

P3071 [USACO13JAN] Seating G 题解

时间:2023-12-19 12:15:24浏览次数:22  
标签:P3071 Seating int 题解 tree mid ls 区间 id

题意:维护两个操作,区间推平,求连续 \(0\) 的个数为 \(x\) 的最前位置。

线段树。

因为需要求连续 \(0\) 的个数,所以维护区间左边连续 \(0\) 的最大个数,区间右边连续 \(0\) 的最大个数以及区间连续 \(0\) 的最大个数。

注意修改的时候要看是修改为 \(1\) 还是修改为 \(0\)。

查询的时候如果整个区间连续 \(0\) 的最大个数小于 \(x\) 就操作失败。否则一直往区间连续 \(0\) 的个数大于 \(x\) 的位置跳,优先跳左区间,然后跳中间(左区间的右边和右区间的左边相接),最后跳右区间。

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define ls id << 1
#define rs id << 1 | 1
const int MAXN = 5e5 + 10;
int n,m,x,y,ans;
char op;
struct SegmentTree{int id,l,r,lmx,rmx,sum,tag;}tree[MAXN << 2];
inline void Pushup(int id)
{
	tree[id].sum = max(max(tree[ls].sum,tree[rs].sum),tree[ls].rmx + tree[rs].lmx);
	if(tree[ls].sum == tree[ls].r - tree[ls].l + 1) tree[id].lmx = tree[ls].sum + tree[rs].lmx;
	else tree[id].lmx = tree[ls].lmx;
	if(tree[rs].sum == tree[rs].r - tree[rs].l + 1) tree[id].rmx = tree[rs].sum + tree[ls].rmx;
	else tree[id].rmx = tree[rs].rmx;
}
inline void Pushdown(int id)
{
	if(tree[id].tag == -1) return;
	if(tree[id].tag == 1)
	{
		tree[ls].lmx = tree[ls].rmx = tree[ls].sum = 0;
		tree[rs].lmx = tree[rs].rmx = tree[rs].sum = 0;
		tree[ls].tag = tree[rs].tag = tree[id].tag,tree[id].tag = -1;
	} else
	{
		tree[ls].lmx = tree[ls].rmx = tree[ls].sum = tree[ls].r - tree[ls].l + 1;
		tree[rs].lmx = tree[rs].rmx = tree[rs].sum = tree[rs].r - tree[rs].l + 1;
		tree[ls].tag = tree[rs].tag = tree[id].tag,tree[id].tag = -1;
	}
}
inline void Build(int id,int l,int r)
{
	tree[id].l = l,tree[id].r = r,tree[id].tag = -1;
	tree[id].lmx = tree[id].rmx = tree[id].sum = r - l + 1;
	if(l == r) return;
	int mid = (l + r) >> 1;
	Build(ls,l,mid),Build(rs,mid + 1,r);
	Pushup(id);
}
inline void Update(int id,int l,int r,int a,int b,int c)
{
	if(a <= l && b >= r)
	{
		if(c == 1) tree[id].sum = tree[id].lmx = tree[id].rmx = 0;
		else tree[id].sum = tree[id].lmx = tree[id].rmx = r - l + 1;
		tree[id].tag = c;return;
	}
	Pushdown(id);
	int mid = (l + r) >> 1;
	if(a <= mid) Update(ls,l,mid,a,b,c);
	if(b > mid) Update(rs,mid + 1,r,a,b,c);
	Pushup(id);
}
inline int Query(int id,int l,int r,int a,int b,int c)
{
	Pushdown(id);
	if(l == r) return l;
	int mid = (l + r) >> 1;
	if(tree[ls].sum >= c) return Query(ls,l,mid,a,b,c);
	else if(tree[ls].rmx + tree[rs].lmx >= c) return mid - tree[ls].rmx + 1;
	else return Query(rs,mid + 1,r,a,b,c);
}
signed main()
{
	cin >> n >> m;
	Build(1,1,n);
	while(m--)
	{
		cin >> op;
		if(op == 'A')
		{
			cin >> x;
			if(tree[1].sum < x) ans++;
			else 
			{
				int pos = Query(1,1,n,1,n,x);
				Update(1,1,n,pos,pos + x - 1,1);
			}
		} 
		else cin >> x >> y,Update(1,1,n,x,y,0);
	}
	cout << ans;
	return 0;
}

标签:P3071,Seating,int,题解,tree,mid,ls,区间,id
From: https://www.cnblogs.com/Creeperl/p/17913404.html

相关文章

  • P2664 树上游戏 题解
    原题链接:P2664。题意:给定一棵树,每个点都有一个颜色\(c_{i}\)。对于每一个点\(i\),求出\(\sum_{j=1}^{n}s(i,j)\)的值。其中\(s(i,j)\)表示点\(i\)到点\(j\)的颜色数量。路径相关,考虑点分治。假设当前的重心为\(u\),那么对\(u\)自己的贡献就是\(u\)到\(u\)的所有......
  • [ABC328F] Good Set Query 题解
    复习了一下边带权并查集板子。设\(d_{x}\)表示当前点到它所在连通块根节点的距离。合并点\(x\)和点\(y\)所在两个连通块时需要更新\(d\)。因为将\(x\)点所在连通块的根节点的父亲节点设为了\(y\)点所在连通块的根节点,所以有\(x\toy\toFind(y)=x\toFind(x)\to......
  • P6370 [COCI2006-2007#6] KAMEN 题解
    原题链接:P6370思路题意不多赘述。首先这道题的\(60\)分暴力很好打,直接按题目中的操作做即可,时间复杂度\(O(nr)\)。考虑优化暴力。我们会发现很多次石头的起始点为同一列的情况,其实每一次下落的轨迹是差不多的。具体来讲应该是第一次下落的轨迹一定包含了后面每一次的轨迹。......
  • P4786 [BalkanOI2018] Election 题解
    题意给定一个长度为\(n\)的字符串\(s\),有\(m\)个询问,每次询问最少需要删掉多少个字符才能使\(l\)到\(r\)组成的字符串当中的每一个前缀和后缀都满足C的数量不小于T的数量。思路因为要满足C的数量不小于T的数量,我们不妨设字符C的位置的值为\(1\),字符S的位......
  • P8386 [PA2021] Od deski do deski 题解
    显然是一道计数dp。dp状态应该是最难的一部分了,个人认为这种状态设计得比较巧妙。如果像我刚开始一样设\(dp_{i,j}\)表示序列中一共有\(i\)个数,序列最后一个数为\(j\)的合法方案数的话,那么方程就会变得很不好转移,因为我们不知道当前的\(j\)和之前的某些数能不能匹配上,......
  • C0328 【1005 C组】模拟测试 斜率 题解
    原题链接:斜率。题意在一个平面直角坐标系中,给定\(n\)个点的横纵坐标,求出哪两个点所构成的连线的斜率最接近\(\frac{P}{Q}\)。数据范围:\(n\le1000000\)。思路显然这是一道数学题,不能直接暴力去找答案。首先我们可以弱化一下题目,求出斜率最接近\(y=0\)即\(x\)轴的两......
  • Omkar and Akmar 题解
    题意:有一个\(n\)个点的环,以及两个人。每个人可以向环中任意一个位置放置一个\(A\)或者\(B\),但是相邻的位置不能相同,不能行动者输。问最终的局面有多少种。一个结论是:后手必胜。证明:最终肯定不可能出现两个连续的空格,否则一定可以在其中一个上填\(A\)或\(B\)。所以最多只......
  • Square-free division (easy version) 题解
    题意:给定一个长度为\(n\)的序列,求最少能将这个序列分成多少段使得任意一段中不存在两个数的积为完全平方数。一个小Trick:如果两个数乘起来为平方数,可以先将每个数的平方因子除掉,然后这两个数必然相等。于是这道题被转化为了一个区间不能有相等的值,这就很典了。设\(pos_{a_{i......
  • Animals and Puzzle 题解
    原题链接:CF713D题意:给定一个\(n\timesm\)的地图\(a\),\(a_{i}\)为\(0\)或\(1\)。有\(t\)次询问,每次询问给定一个矩形,求出这个矩形中最大的由\(1\)构成的正方形的边长是多少。首先考虑预处理出\(d_{i,j}\)表示以\((i,j)\)为左上角的最大正方形边长是多少。对于每......
  • C0392 B 【1109 B组】预处理器 题解
    题意:求有多少个长度为\(n\)的数组\(a\)满足以下条件。条件一:\(l_{i}\lea_{i}\ler_{i}\)。条件二:\(a_{i}\)模\(2\)等于\(p_{i}\)。条件三:\(s\le\suma_{i}\let\)。求答案模\(mod\)的值,\(mod\)不一定是一个质数。数据范围:\(n\le13\)。又积累到一......