CSP-S开小灶3 滚【分块莫队】

https://tg.hszxoj.com/contest/458/problem/2

其实我开始思路是对的,莫队维护询问的每一步操作对区间出现次数的改变,但是几个优化和关键性的地方想错了:
(1)不能用可重复集合,不然你就需要在set里跳很多次。直接cnt记录每种出现次数出现的次数就行。
(2)在寻找合法的时候,对于x,只要他的前驱合法一定合法,所以判断相邻就可以。

点击查看代码






#include<bits/stdc++.h>
using namespace std;
#define _f(i,a,b) for(register int i=a;i<=b;++i)
#define f_(i,a,b) for(register int i=a;i>=b;--i)
#define chu printf
#define ll long long
#define ull unsigned long long
inline ll re()
{
    ll x=0,h=1;
    char ch=getchar();
    while(ch<'0'||ch>'9')
    {
        if(ch=='-')h=-1;
        ch=getchar();
    }
    while(ch<='9'&&ch>='0')
    {
        x=(x<<1)+(x<<3)+(ch^48);
        ch=getchar();
    }
    return x*h;
}
const int N=2e5+10;
int n,m;
int a[N],w[N],base,cnt[N];//cnt是出现次数,也是这个数在不在set里面
int vis[N];
set<int>s;
struct QUERY
{
    int l,r,k,id;//但是这个k啊,只能O(n)扫了,
    bool operator <(const QUERY&A)const
    {
        int code1=(r+1)/base,code2=(A.r+1)/base;
        if(code1!=code2)return code1<code2;
        if(code1&1)return l<A.l;
        return l>A.l;
    }
}q[N];
int ans[N];
set<int>::iterator it1,it2,ls;
inline void add(int pos)
{
   int vl=a[pos];
   if(cnt[vl])//如果set里面有出现次数
   {
       vis[cnt[vl]]--;
       if(!vis[cnt[vl]])s.erase(cnt[vl]);//只有这一个数占据
   }
   cnt[vl]++;
   vis[cnt[vl]]++;
   if(vis[cnt[vl]]==1)s.insert(cnt[vl]);
}
inline void del(int pos)
{
   int vl=a[pos];
   if(cnt[vl])//如果set里有这个出现次数
   {
       vis[cnt[vl]]--;
       if(!vis[cnt[vl]])s.erase(cnt[vl]);
   }
   cnt[vl]--;
   if(!cnt[vl])//没有出现什么都不加了
   return;
   vis[cnt[vl]]++;
   if(vis[cnt[vl]]==1)
   s.insert(cnt[vl]);
}
int main()
{
  // freopen("1.in","r",stdin);
   //freopen("a.out","w",stdout);
   n=re(),m=re();
    _f(i,1,n)a[i]=re();
    _f(i,1,n)w[i]=re();
    base=sqrt(n);
    _f(i,1,m)
    q[i].l=re(),q[i].r=re(),q[i].k=re(),q[i].id=i;
    sort(q+1,q+1+m);
    int l=1,r=0;
    _f(i,1,m)
    {
        if(q[i].r-q[i].l==0)
        {
            ans[q[i].id]=-1;continue;
        }
        while(q[i].r>r)add(++r);
        while(q[i].l<l)add(--l);
        while(q[i].r<r)del(r--);
        while(q[i].l>l)del(l++);
        int Mx=-1;
        it1=s.begin(),it2=next(s.begin());
        for(;it2!=s.end();++it2,++it1)
        {
            if((*it2)-(*it1)<=q[i].k)Mx=max(Mx,w[*it2]);
        }
        ans[q[i].id]=Mx;
    }
    _f(i,1,m)chu("%d\n",ans[i]);
    return 0;
}
/*
7 3
1 3 3 2 1 3 3
1 2 3 4 5 6 7
1 7 1
3 5 1
5 7 1


2
-1
2

10 3
1 2 3 3 2 3 3 2 4 4
1 1 4 5 1 4 1 9 1 9
2 6 1
3 9 3
1 10 1
*/
posted on 2022-09-13 07:41  HZOI-曹蓉  阅读(11)  评论(0编辑  收藏  举报