可重集【线段树】

>Link

luogu T202677


>Description

在这里插入图片描述
n , m ≤ 3 ∗ 1 0 5 n,m\le3*10^5 n,m3105


>解题思路

一开始想到了线段树,但是不知道怎么处理QwQ 感觉线段树是错的就没继续想了(特别是那个模数可能是合数)

我们可以发现实际上对于同一个操作,操作一和操作二是一一对应的
那我们就预处理先把他们对应起来

线段树肯定是在时间上面建的
如果遇到加操作,就在线段树上对应的位置修改成x
如果遇到减操作,就在这个减操作对应的加操作的位置上,把他修改成1(在加操作上修改,这样保证了只有它对应的加操作出现过,它才会生效)
对于询问一个区间 [ l , r ] [l,r] [l,r],我们把 [ 1 , r ] [1,r] [1,r] 的操作都加进线段树,然后询问 [ l , r ] [l,r] [l,r]

那这样会T,所以我们可以离线询问,把询问按照 r r r 从小到大排个序

(然后随便说一下,用树状数组的话要用扩欧求逆元,会T)


>代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <stack>
#define N 300010
#define LL long long
using namespace std;

stack<int> st;
struct node
{
    
    
	int tim, type, op; LL x;
} a[N];
struct node2
{
    
    
	int l, r, id;
} b[N];
int n, m;
LL Mod, t[N * 5], ans[N];

bool cmp1 (node aa, node bb)
{
    
    
	if (aa.x != bb.x) return aa.x < bb.x;
	return aa.tim < bb.tim;
}
bool cmp2 (node aa, node bb) {
    
    return aa.tim < bb.tim;}
bool cmp3 (node2 aa, node2 bb)
{
    
    
	if (aa.r != bb.r) return aa.r < bb.r;
	return aa.l < bb.l;
}
void build (int k, int l, int r)
{
    
    
	t[k] = 1 % Mod;
	if (l == r) return;
	int mid = (l + r) / 2;
	build (k * 2, l, mid);
	build (k * 2 + 1, mid + 1, r);
}
void modify (int k, int l, int r, int x, LL val)
{
    
    
	if (l == r)
	{
    
    
		t[k] = val % Mod;
		return;
	}
	int mid = (l + r) / 2;
	if (x <= mid) modify (k * 2, l, mid, x, val);
	if (mid + 1 <= x) modify (k * 2 + 1, mid + 1, r, x, val);
	t[k] = t[k * 2] * t[k * 2 + 1] % Mod;
}
LL ask (int k, int l, int r, int ll, int rr)
{
    
    
	if (ll <= l && r <= rr) return t[k];
	LL ret = 1;
	int mid = (l + r) / 2;
	if (ll <= mid) ret = ret * ask (k * 2, l, mid, ll, rr) % Mod;
	if (mid + 1 <= rr) ret = ret * ask (k * 2 + 1, mid + 1, r, ll, rr) % Mod;
	return ret;
}

int main()
{
    
    
//	freopen ("example2.in", "r", stdin);
//	freopen ("check.out", "w", stdout);
	scanf ("%d%d%lld", &n, &m, &Mod);
	for (int i = 1; i <= n; i++)
	{
    
    
		scanf ("%d%lld", &a[i].type, &a[i].x);
		a[i].tim = i;
	}
	sort (a + 1, a + 1 + n, cmp1);
	for (int i = 1; i <= n; i++)
	{
    
    
		if (a[i].x != a[i - 1].x)
		  while (!st.empty()) st.pop();
		if (a[i].type == 1) st.push (a[i].tim);
		else if (!st.empty())
		  a[i].op = st.top(), st.pop();
	}
	sort (a + 1, a + 1 + n, cmp2);
	for (int i = 1; i <= m; i++)
	{
    
    
		scanf ("%d%d", &b[i].l, &b[i].r);
		b[i].id = i;
	}
	sort (b + 1, b + 1 + m, cmp3);
	build (1, 1, n);
	int p = 0;
	for (int i = 1; i <= m; i++)
	{
    
    
		while (p < b[i].r)
		{
    
    
			p++;
			if (a[p].type == 1)
			  modify (1, 1, n, a[p].tim, a[p].x);
			else if (a[p].op) modify (1, 1, n, a[p].op, 1);
		}
		ans[b[i].id] = ask (1, 1, n, b[i].l, b[i].r);
	}
	for (int i = 1; i <= m; i++)
	  printf ("%lld\n", ans[i]);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_43010386/article/details/121094188