>Link
luogu T202677
>Description
n , m ≤ 3 ∗ 1 0 5 n,m\le3*10^5 n,m≤3∗105
>解题思路
一开始想到了线段树,但是不知道怎么处理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;
}