美文网首页
线段树优化建图

线段树优化建图

作者: 云中翻月 | 来源:发表于2020-11-25 07:37 被阅读0次

    适用题目特征

    一个点/区间向一个区间上的所有点建边。

    原理

    对每个需要建边的区间上的所有点建立一棵线段树,通过向线段树建边,取代向线段树上所有叶子节点建边的操作。

    例题

    Luogu P3588
    代码如下

    /*
    Luogu P3588
    */
    #define method_1
    #ifdef method_1
    /*
    
    */
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<set>
    #include<map>
    #include<queue>
    #include<stack>
    #include<vector>
    #include<cstring>
    #include<cstdlib>
    #include<iomanip>
    #include<ctime>
    #include<string>
    #include<bitset>
    #define D(x) cout<<#x<<" = "<<x<<"  "
    #define E cout<<endl
    #define rep(i,s,t) for(int i=(s);i<=(t);i++)
    #define rep0(i,s,t) for(int i=(s);i<(t);i++)
    #define rrep(i,t,s) for(int i=(t);i>=(s);i--)
    using namespace std;
    typedef long long ll;
    typedef pair<int,int>pii;
    const int maxn=5e5+5;
    const int INF=0x3f3f3f3f;
    int n,s,m;
    int id[maxn*(4+1)],cnt;
    struct segmentTree{
        int l,r;
    }tr[maxn*(4+1)];
    int head[maxn*(4+1)],tot=1;
    int in[maxn];
    struct node{
        int from,to,w;
    }edge[(maxn*(4+1))<<1];
    void add(int from,int to,int w){
        edge[++tot].from=head[from],edge[tot].to=to,edge[tot].w=w,head[from]=tot,in[to]++;
    }
    void build(int rt,int l,int r){
        tr[rt].l=l,tr[rt].r=r;
        if(l==r) {id[rt]=l;return;}
        id[rt]=++cnt;
        int mid=l+r>>1;
        build(rt<<1,l,mid),build(rt<<1|1,mid+1,r);
        add(id[rt<<1],id[rt],0),add(id[rt<<1|1],id[rt],0);
    }
    void update(int rt,int l,int r,int x){
        if(l<=tr[rt].l&&tr[rt].r<=r){add(id[rt],x,0);return;}
        int mid=tr[rt].l+tr[rt].r>>1;
        if(l<=mid) update(rt<<1,l,r,x);
        if(r>mid) update(rt<<1|1,l,r,x);
    }
    queue<int>q;
    int a[maxn*(4+1)],dis[maxn*(4+1)];
    int v[maxn*(4+1)];
    void toposort(){
        rep(i,1,cnt) {dis[i]=dis[i]?dis[i]:1;if(!in[i]) q.push(i);}
        while(q.size()){
            int x=q.front();q.pop();v[x]=1;
            for(int i=head[x];i;i=edge[i].from){
                int y=edge[i].to,w=edge[i].w;
                dis[y]=max(dis[x]+w,dis[y]);
                if(a[y]&&dis[y]>a[y]){printf("NIE");exit(0);}
                if(--in[y]==0) q.push(y);
            }
        }
    }
    void solve(){
        int l,r,k;
        rep(i,1,m){
            scanf("%d%d%d",&l,&r,&k);
            int pre=l-1;cnt++;
            int x;while(k--){
                scanf("%d",&x);
                if(x>pre+1) update(1,pre+1,x-1,cnt);
                add(cnt,x,1);pre=x;
            }
            if(pre<r) update(1,pre+1,r,cnt);
        }
        toposort();
        rep(i,1,n) if(!v[i]||dis[i]>1e9){printf("NIE");return;}
        printf("TAK\n");
        rep(i,1,n) printf("%d ",dis[i]);
    }
    int main() {
    //  ios::sync_with_stdio(false);
    //  freopen("PUS.in","r",stdin);
        scanf("%d%d%d",&n,&s,&m);cnt=n;
        build(1,1,n);
        int p,d;
        rep(i,1,s) scanf("%d%d",&p,&d),a[p]=dis[p]=d;
        solve();
        return 0;
    }
    #endif
    #ifdef method_2
    /*
    
    */
    
    #endif
    #ifdef method_3
    /*
    
    */
    
    #endif
    

    相关文章

      网友评论

          本文标题:线段树优化建图

          本文链接:https://www.haomeiwen.com/subject/qmvwiktx.html