LGP11191 [KDOI R10] 超级演出 学习笔记

LGP11191 [KDOI R10] 超级演出 学习笔记

Luogu Link

题意简述

做法解析

(待完善)
(朴素算法:)

(发现瓶颈在出度太大又在A中频繁出现的点)

考虑对点的出度进行根号分治。如果 oudu>sqrtm,那么就不要自己从后继取了,转而:让后继在反图上给自己连边,让后继更新好信息给自己,这样可以减少很多导致复杂度出问题的冗余,把复杂度稳稳控制在 mm

代码实现

#include <bits/stdc++.h>
using namespace std;
namespace obasic{
    typedef vector<int> vecint;
    template <typename _T>
    void readi(_T &x){
        _T k=1;x=0;char ch=getchar();
        for(;!isdigit(ch);ch=getchar())if(ch=='-')k=-1;
        for(;isdigit(ch);ch=getchar())x=(x<<3)+(x<<1)+ch-'0';
        x*=k;return;
    }
    template <typename _T>
    void writi(_T x){
        if(x<0)putchar('-'),x=-x;
        if(x>9)writi(x/10);
        putchar(x%10+'0');
    }
    template <typename _T>
    void maxxer(_T &x,_T y){x=max(x,y);}
};
using namespace obasic;
const int MaxN=2e5+5;
int Tpn,N,M,P,Q,X,Y,A[MaxN],B;
int isn[MaxN],oud[MaxN];
int aw[MaxN],gw[MaxN],rw[MaxN];
vecint Gr[MaxN],Rg[MaxN];
void addedge(int u,int v){
    Gr[u].push_back(v);
    oud[u]++;if(v==1)isn[u]=1;
}
struct quer{int l,id;};
vector<quer> F[MaxN];
int lst[MaxN];
struct BinidTree{
    int n,t[MaxN];
    void init(int x){n=x,fill(t,t+n+1,0);}
    int lowbit(int x){return x&(-x);}
    void add(int p,int x){for(;p<=n;p+=lowbit(p))t[p]+=x;}
    int gts(int p){int res=0;for(;p;res+=t[p],p-=lowbit(p));return res;}
    int getsum(int l,int r){return gts(r)-gts(l-1);}
}BiT;
int ans[MaxN];
int main(){
    readi(Tpn);
    readi(N),readi(M),readi(P),readi(Q);B=sqrt(M);
    for(int i=1;i<=M;i++)readi(X),readi(Y),addedge(X,Y);
    for(int u=1;u<=N;u++)if(oud[u]>=B)for(int v : Gr[u])Rg[v].push_back(u);
    BiT.init(P);for(int i=1;i<=P;i++)readi(A[i]);
    for(int i=1;i<=P;i++){
        if(isn[A[i]])aw[i]=i;
        else if(oud[A[i]]>=B)aw[i]=rw[A[i]];
        else for(int v : Gr[A[i]])maxxer(aw[i],gw[v]);
        gw[A[i]]=aw[i];for(int v : Rg[A[i]])maxxer(rw[v],aw[i]);
    }
    for(int i=1;i<=Q;i++)readi(X),readi(Y),F[Y].push_back({X,i});
    for(int i=1;i<=P;i++){
        if(lst[A[i]])BiT.add(lst[A[i]],-1);
        if(aw[i])BiT.add(aw[i],1),lst[A[i]]=aw[i];
        for(auto [cl,cid] : F[i])ans[cid]=N-1-BiT.getsum(cl,P);
    }
    for(int i=1;i<=Q;i++)writi(ans[i]),puts("");
    return 0;
}

反思总结

图论问题中,对于通过边邻接关系转移的信息更新,可能既可以自己从别人(前驱、后继)那拿,也可以让别人(前驱、后继)给自己。通常,这两种做法的复杂度是不完全一样的。有可能当自己入度或出度太多,又要反复从别人那拿时,那就劣了。不如考虑让别人给自己。其中的复杂度可能因为根号分治的原理优化到 NN 级而可以接受。

posted @   矞龙OrinLoong  阅读(2)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
点击右上角即可分享
微信分享提示