[省选联考 2025] 追忆 题解

[省选联考 2025] 追忆 题解

小丑来改省选题了

首先发现问题不弱于求导出子图,复杂度大概就是 \(O(\dfrac{n^2}{w})\) 的样子

先说一个大常熟做法,胜在简单

考虑特殊性质

容易发现性质C看起来就非常可做,去掉了 \(l,r\) 的限制使得我们拥有足够的复杂度去做后面的东西

考虑对操作分块:先bitset预处理出一个点可达的所有点,把修改全当成赋值,对于块内的查询直接暴力查看是否有贡献就好了,然后将所有修改位置置为 \(0\),在dag 上跑一遍 dp 即可得到答案,复杂度显然是 \(O(\dfrac{n^2}{w}+n\sqrt n)\)

我们看看这个做法还能不能拿到更高的分

后面的东西里面都有区间,尝试对 \(a\) 进行分块,重构的时候每次求出连续的一段 \(a\) 对当前点的贡献

如果暴力做这个东西的话会比刚才多个块数(要跑块数遍)复杂度是 \(O((n+m)\dfrac{n}{B1}\dfrac{q}{B2}+q(\dfrac{n}{B1}+B1+B2)))\)

因为 \(n,m,q\) 同阶,把柿子写好看点就得到了 \(O((\dfrac{n^3}{B1B2}+\dfrac{n^2}{B1}+nB1+nB2)))\)

容易发现只要取 \(B1=B2=n^\frac{2}{3}\) 即可获得 \(O(\dfrac{n^2}{w}+n^\frac{5}{3})\) 的复杂度,算出来应该是可以通过的,不过可能需要卡常,期望得分 \(88\sim 100\)

但是我场上以为这个东西是 \(O(n^2)\) 的,没仔细分析复杂度,没有调块长,甚至改题的时候也没想到这个东西,还强行上了个值域分块和bitset

接下来是一个真的需要值域分块和bitset的做法,复杂度是 \(O(\dfrac{n^2}{w}+n\sqrt{n})\),并且是在线做法,薄纱上面做法

首先肯定依然需要对 \(a\) 进行分块,这回我们换个方向来做,从 D 性质入手

D 性质意味着我们不再有数组 \(b\) 了,只剩下 \(a\),要求的就是询问的 \(a\) 区间与可达点的交集中最大的 \(a\) 权值

那么现在我们可以使用 bitset 存每一块中的点所对应的标号,之后从大到小遍历每一块,如果和可达点有交,证明答案一定在这一段内

暴力去做的话复杂度是 \(O(\dfrac{n^2}{w}\sqrt{n})\) 发现复杂度瓶颈在于遍历所有整块,而且一个事实是修改是 \(O(1)\)

那么我们发现可以维护各个块的后缀和,之后在整块上二分即可做到 \(O(\sqrt n)\) 修改 \(O(\dfrac{n}{w}\log\sqrt{n})\) 回答询问

这时候已经可以通过性质 D 了,考虑扩展

发现同时有 \(a\)\(b\) 的时候可以对 \(a\)\(b\) 同时分块,然后同时维护上面那个东西(合法的点的集合),因为是排列,所以 bitset 是可以差分的,查询和可达点的交就是 \(O(\dfrac{n^2}{w})\) 的,后面半部分在 \(b\) 上做就好了

为了通过所有数据,我们还需要去掉那个 \(\log n\)(感觉其实调一下块长是不是也没什么问题),发现在后缀和的形式中交一定是单调的

初始认为答案在第0块,手写bitset,遍历每一位,如果当前下一块的这一位的 ull 和这个和上面的合法的点有交,说明答案一定在下一块或者更后面的位置,指针加,否则的话说明bitset前面的点不会有其他贡献

这样的话查询只需要遍历整个bitset,复杂度 \(O(\dfrac{n^2}{w}+n\sqrt{n})\)

贴个代码
#include<bits/stdc++.h>
using namespace std;
using llt=long long;
using ull=unsigned long long;
const int N=100010,W=64,B=400,Len=N/W+1;
int c,T,n,m,q,a[N],ra[N],b[N],rb[N],in[N],S,L[N],R[N];bool U[N];
struct GRAPH
{
    int head[N],to[N<<1],nxt[N<<1],siz;
    void add(int st,int ed){to[++siz]=ed,nxt[siz]=head[st],head[st]=siz;}
    void clear(){for(int i=1;i<=n;i++)   head[i]=0;siz=0;}
}G;
struct BITSET
{
    ull a[Len];
    void reset(){memset(a,0,sizeof(a));}
    void mod(int id,bool val)
    {
        int u=0;while(id>=W) id-=W,u++;
        if(val) a[u]|=(1ull<<id);
        else a[u]&=~(1ull<<id);
    }
    BITSET & operator |=(BITSET &rhs){for(int i=0;i<Len;i++)  this->a[i]|=rhs.a[i];return *this;}
    BITSET & operator &=(BITSET &rhs){for(int i=0;i<Len;i++)  this->a[i]&=rhs.a[i];return *this;}
    BITSET & operator ^=(BITSET &rhs){for(int i=0;i<Len;i++)  this->a[i]^=rhs.a[i];return *this;}
    bool get(int id){int u=0;while(id>=W) id-=W,u++;return (a[u]>>id)&1;}
    ull & operator[](int id){return a[id];}
}bit[N],Ba[N/B+1],Bb[N/B+1],us;
void Pre(int now)
{
    U[now]=1;bit[now].mod(now,1);
    for(int i=G.head[now];i;i=G.nxt[i])
    {    
        if(!U[G.to[i]])  Pre(G.to[i]);
        bit[now]|=bit[G.to[i]];
    }
}

int main()
{
    #ifdef LOCAL
        freopen("1.in","r",stdin);
        freopen("1.out","w",stdout); 
    #endif
    scanf("%d%d",&c,&T);
    while(T--)
    {
        scanf("%d%d%d",&n,&m,&q);S=0;
        for(int i=1;i<=m;i++){int u,v;scanf("%d%d",&u,&v),G.add(u,v);}
        for(int i=1;i<=n;i++) {if(i%B==1) R[S]=i-1,S++,L[S]=i;in[i]=S;}R[S]=n;
        for(int i=1;i<=n;i++)   scanf("%d",&a[i]),ra[a[i]]=i,Ba[in[a[i]]].mod(i,1);
        for(int i=1;i<=n;i++)   scanf("%d",&b[i]),rb[b[i]]=i,Bb[in[b[i]]].mod(i,1);
        for(int i=1;i<=n;i++)   if(!U[i])   Pre(i);
        for(int i=S-1;i>=0;i--)   Ba[i]|=Ba[i+1],Bb[i]|=Bb[i+1];
        for(int i=1;i<=q;i++)   
        {
            int op,u,v,w;
            scanf("%d",&op);
            if(op==1) 
            {
                scanf("%d%d",&u,&v);
                if(a[u]>a[v])   swap(u,v);
                for(int i=in[a[u]]+1;i<=in[a[v]];i++)   Ba[i].mod(u,1);
                for(int i=in[a[u]]+1;i<=in[a[v]];i++)   Ba[i].mod(v,0);
                swap(a[u],a[v]);ra[a[u]]=u;ra[a[v]]=v;
            }
            else if(op==2)
            {
                scanf("%d%d",&u,&v);
                if(b[u]>b[v])   swap(u,v);
                for(int i=in[b[u]]+1;i<=in[b[v]];i++)   Bb[i].mod(u,1);
                for(int i=in[b[u]]+1;i<=in[b[v]];i++)   Bb[i].mod(v,0);
                swap(b[u],b[v]);rb[b[u]]=u;rb[b[v]]=v;
            }
            else 
            {
                scanf("%d%d%d",&w,&u,&v);
                us.reset();
                if(in[u]==in[v]){for(int i=u;i<=v;i++)  us.mod(ra[i],1);}
                else
                {
                    us=Ba[in[v]];us^=Ba[in[u]+1];
                    for(int i=u;i<=R[in[u]];i++)    us.mod(ra[i],1);
                    for(int i=L[in[v]];i<=v;i++)    us.mod(ra[i],1);
                }
                us&=bit[w];int to=0;
                for(int i=0;i<Len&&to<S;)
                {
                    if((Bb[to+1][i]&us[i])!=0)    to++;
                    else i++;
                }
                if(to==0)    puts("0");
                else
                {
                    for(int i=R[to];i>=L[to];i--)
                        if(us.get(rb[i]))   {printf("%d\n",i);break;}
                }
            }
        }
        G.clear();for(int i=1;i<=n;i++)  U[i]=0,bit[i].reset();for(int i=1;i<=S;i++)   Ba[i].reset(),Bb[i].reset();
    }
    return 0;
}
posted @ 2025-03-23 19:41  wang54321  阅读(116)  评论(4)    收藏  举报