线段树优化建图

适用题目特征

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

原理

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

例题

Luogu P3588
代码如下

/*
Luogu P3588
*/
#define method_1
#ifdef method_1
/*

*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define D(x) cout<<#x<<" = "<=(s);i--)
using namespace std;
typedef long long ll;
typedef pairpii;
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);
}
queueq;
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(pre1e9){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

你可能感兴趣的:(线段树优化建图)