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

线段树优化建图

作者: 云中翻月 | 来源:发表于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

相关文章

  • 线段树优化建图

    适用题目特征 一个点/区间向一个区间上的所有点建边。 原理 对每个需要建边的区间上的所有点建立一棵线段树,通过向线...

  • 解析·优化 ZKW线段树

    德鲁伊!大自然已经听命于我了!死亡之翼长子奈法利安 ZKW天下第一!摘自某群聊天记录 ZKW线段树,即非递归形式的...

  • 算法模板(七) 线段树

    线段树单点操作 线段树区间操作

  • 数据结构-线段树

    实现一个线段树 下面实现的线段树,有三个功能: 把数组构建成一颗线段树 线段树的修改 线段树的查询 303号问题 ...

  • HDU3974(Assign the task)

    链接:https://vjudge.net/problem/HDU-3974思路:终于明白了dfs序建线段树是什么...

  • DP训练——线段树优化DP

    线段树优化DP HDU3698题意给定的矩阵和,须从矩阵的每行选择一个数字,使得数字和最小。选择时须保证前后选择的...

  • 线段树系列之——区间更新

    第三篇线段树了——重点不在于解决题目,通过题目理解线段树才是重点 前面写了一篇关于线段树的单点更新,线段树的单点更...

  • 线段树模板

    线段树 线段树基本概念 概述 线段树,类似区间树,是一个完全二叉树,它在各个节点保存一条线段(数组中的一段子数组)...

  • 线段树专题整理

    待更新 线段树讲解(未读)线段树模板(未读) 模板 求区间总和 A - 敌兵布阵 HDU - 1166 题意 线段...

  • 线段树 02 构建线段树

    构建线段树 线段树的每个节点除了天然的对应一段长度外,不一定赋予其上的意义就是区间元素的和,所以两个节点向上汇聚成...

网友评论

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

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