P3674 小清新人渣的本愿 (bitset+莫队)

给你一个序列a,长度为n,有m次操作,每次询问一个区间是否可以选出两个数它们的差为x,或者询问一个区间是否可以选出两个数它们的和为x,或者询问一个区间是否可以选出两个数它们的乘积为x ,这三个操作分别为操作1,2,3

对于操作3,我们可以很容易通过枚举约数得到。
离线操作,考虑莫队
对于操作1,询问实际上问的就是区间是否存在a和x-a,因为数据范围较小,用bitset维护每个值
对于操作2,考虑一个较大值 m a x n maxn maxn ,根据 ( m a x n − i ) − ( m a x n − k ) = ( k − i ) (maxn-i)-(maxn-k)=(k−i) (maxni)(maxnk)=(ki),维护 m a x n − a [ i ] maxn-a[i] maxna[i]即可

#include 
using namespace std;
#define rep(i,a,n) for (int i=a;i
#define per(i,a,n) for (int i=n-1;i>=a;i--)
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define SZ(x) ((int)(x).size())
#define de(c) cout << #c << " = " << c << endl
#define dd(c) cout << #c << " = " << c << " "
typedef vector<int> VI;
typedef long long ll;
typedef pair<int,int> PII;
mt19937 mrand(random_device{}());
const ll mod=1000000007;
int rnd(int x) { return mrand() % x;}
ll powmod(ll a,ll b) {ll res=1;a%=mod; assert(b>=0); for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
const int maxn = 1e5+50;

bitset<maxn+50> s1,s2;
struct query { int L, R, id,op,val; } q[maxn];
int ans[maxn+50];
int a[maxn+50];
int cnt[maxn+50];
int n,m,unit;

void add(int x)
{
	cnt[a[x]]++;
	if(cnt[a[x]] == 0)
    s1[a[x]] = s2[maxn-a[x]] = cnt[a[x]];
    else
    s1[a[x]] = s2[maxn-a[x]] = 1;
}

void del(int x)
{
	cnt[a[x]]--;
	if(cnt[a[x]] == 0)
	s1[a[x]] = s2[maxn-a[x]] = cnt[a[x]];
    else
    s1[a[x]] = s2[maxn-a[x]] = 1;
}


void solve(query node[], int m)
{
    memset(ans, 0, sizeof(ans));
    s1.reset();
    s2.reset();
    memset(cnt, 0, sizeof(cnt));
    sort(node+1, node + m+1, [](query a, query b) {
        if(a.L / unit == b.L / unit)
        {
            return a.R < b.R;
        }
        return a.L < b.L;
    });
    // rep(i,1,m+1)
    // {
    //     dd(node[i].L),dd(node[i].R),dd(node[i].id),dd(node[i].op),de(node[i].val);
    // }
    int L = 1, R = 0;
    for (int i = 1; i < m+1; i++)
    {
    	while (node[i].L > L) del(L++);
        while (node[i].L < L) add(--L);
        while (node[i].R > R) add(++R);
        while (node[i].R < R) del(R--);
        // dd(L),de(R);
        if(node[i].op == 1)
        {
        	ans[node[i].id] = (s1&(s1<<node[i].val)).any();
        }
        else if(node[i].op == 2)
        {
        	ans[node[i].id] = (s1&(s2>>(maxn-node[i].val))).any();	
        }
        else
        {
        	for(int j=1;j*j<=node[i].val;j++) 
        	if(node[i].val % j ==0)
            {
                // de(s1[4]);
                if(s1[j] && s1[node[i].val/j]) 
                    {
                        ans[node[i].id]=1;
                    }
            }
        }
        // ans[node[i].id] = tmp;
    }
}

int main(int argc, char const *argv[])
{
	ios_base::sync_with_stdio(false), cin.tie(0), cout.tie(0);
	cin >> n >> m;
	unit = int(sqrt(n)+0.5);
	rep(i,1,n+1)
	{
		cin >> a[i];
	}
	int op,l,r,x;
	rep(i,1,m+1)
	{
		cin >> op >> l >> r >> x;
		q[i].op = op;
		q[i].L = l;
		q[i].R = r;
		q[i].val = x;
		q[i].id = i;
	}
	solve(q,m);
	rep(i,1,m+1)
	{
		if(ans[i])
		{
			cout << "hana"<<endl;
		}
		else
		{
			cout << "bi" << endl;
		}
	}
	return 0;
}
/*
node[i].L = 1 node[i].R = 1 node[i].id = 1 node[i].op = 2 node[i].val = 2
node[i].L = 1 node[i].R = 1 node[i].id = 3 node[i].op = 3 node[i].val = 1
node[i].L = 1 node[i].R = 2 node[i].id = 2 node[i].op = 1 node[i].val = 2
node[i].L = 2 node[i].R = 3 node[i].id = 5 node[i].op = 1 node[i].val = 4
node[i].L = 5 node[i].R = 5 node[i].id = 4 node[i].op = 3 node[i].val = 16
*/

你可能感兴趣的:(acm,数据结构)