題目傳送門
題目大意
給定 \(n\) 個方程,\(Q\) 次詢問,每次詢問區間 \([l,r]\) 中有多少個數是這 \(n\)
解題思路
算法:離散化 + 前綴和(離線算法)。
前置算法模板:離散化、前綴和。
看到區間首先想到將這 \(n\) 個方程的解標記起來(一個數是方程的解則標記為 \(1\),否則為 \(0\)),求這個標記數組的區間和,那麼我們可以維護這個數組的前綴和來求解。
但是,且慢!!!
\(1\le |a|,|b|,|c|\le 10^9\)
那麼方程的解就是 \(10^9\)
那麼開 map?
要求前綴和顯然也不現實。
於是我看到了:
\(1\le n,Q\le 2\times 10^5\)
那麼總共在解和詢問中出現的數不會超過 \(6\times 10^5\) 個,可以將他們根據大小映射到 \(1\sim 6\times 10^5\)
代碼用的 STL 版本的離散化,比較通俗易懂。
這裏方程的輸入可以用快讀來避免進行字符串的掃描(因為快讀只會讀數字)。
AC Code
#include<iostream>
#include<cstdio>
#include<algorithm>
#define N 600005
#define int long long
using namespace std;
int n,q,cnt;
int bok[N],sum[N],l[N],r[N],x[N];
int re()//樸素的快讀
{
int x=0,p=1;
char y=getchar();
for(;y>'9'||y<'0';y=getchar())
if(y=='-')
p=-p;
for(;y>='0'&&y<='9';y=getchar())
x=x*10+y-'0';
return x*p;
}
void wr(int x)//樸素的快寫
{
if(x<0)
putchar('-'),x=-x;
if(x>9)
wr(x/10);
putchar(x%10+'0');
}
signed main()
{
n=re(),q=re();
for(int i=1;i<=n;i++)
{
int a=re(),b=re(),c=re();
x[i]=(c-b)/a,bok[++cnt]=x[i];//將這個方程解出來,放到待離散化的數組bok中
}
for(int i=1;i<=q;i++)
{
l[i]=re(),r[i]=re();
bok[++cnt]=l[i];
bok[++cnt]=r[i];//將詢問中的l和r放到待離散化的數組中
}
sort(bok+1,bok+cnt+1);//排序
int boks=unique(bok+1,bok+cnt+1)-bok-1;//去重
for(int i=1;i<=n;i++)
x[i]=lower_bound(bok+1,bok+boks+1,x[i])-bok,sum[x[i]]=1;//映射到x數組中並進行標記
for(int i=1;i<=q;i++)
l[i]=lower_bound(bok+1,bok+boks+1,l[i])-bok,
r[i]=lower_bound(bok+1,bok+boks+1,r[i])-bok;//映射到l和r數組中
for(int i=1;i<=boks;i++)
sum[i]+=sum[i-1];//前綴和
for(int i=1;i<=q;i++)
wr(sum[r[i]]-sum[l[i]-1]),putchar('\n');//樸素的前綴和求區間和
return 0;
}