模拟赛T2 线段树优化建图+tarjan+拓扑排序

然而这只是 70pts 的部分分,考场上没想到满分怎么做(现在也不会)

code:

#include <cstdio>
#include <string>
#include <stack>
#include <queue>
#include <cstring>
#include <algorithm>
#define N 100009
#define lson ls[x]
#define rson rs[x]
#define inf 4500000
using namespace std;
void setIO(string s) {
    string in=s+".in";
    string out=s+".out";
    freopen(in.c_str(),"r",stdin);
    freopen(out.c_str(),"w",stdout);
}
int scc;
int cnt;
int n;
int tot;
int edges;
int A[N*5];
int hd[N*5];
int to[N*30];
int nex[N*30];
int ls[N*5];
int rs[N*5];
int vis[N*5];
int dfn[N*5];
int low[N*5];
int id[N*5];
int In[N*5];
int Ou[N*5];
int tag[N*5];
int X[N],L[N],R[N],con[N];
int is[N*5];
stack<int>S;
queue<int>q;
vector<int>G[N*5];
int newnode() {
    return ++tot;
}
void add(int u,int v) {
    // printf("%d %d\n",u,v);
    nex[++edges]=hd[u];
    hd[u]=edges;
    to[edges]=v;
}
void update(int &x,int l,int r,int p) {
    if(l==r) {
        x=p;
        return;
    }
    if(!x) {
        x=newnode();
    }
    int mid=(l+r)>>1;
    if(X[p]<=mid) {
        update(lson,l,mid,p);
    }
    else {
        update(rson,mid+1,r,p);
    }
}
void build(int x) {
    if(lson) {
        add(x,lson);
        build(lson);
    }
    if(rson) {
        add(x,rson);
        build(rson);
    }
}
void Add(int x,int l,int r,int L,int R,int rt) {
    if(!x) {
        return;
    }
    if(l>=L&&r<=R) {
        add(rt,x);
        return;
    }
    int mid=(l+r)>>1;
    if(L<=mid) {
        Add(lson,l,mid,L,R,rt);
    }
    if(R>mid) {
        Add(rson,mid+1,r,L,R,rt);
    }
}
void tarjan(int u) {
    vis[u]=1;
    S.push(u);
    low[u]=dfn[u]=++cnt;
    for(int i=hd[u];i;i=nex[i]) {
        int v=to[i];
        if(!vis[v]) {
            tarjan(v);
            low[u]=min(low[u],low[v]);
        }
        else if(vis[v]==1) {
            low[u]=min(low[u],dfn[v]);
        }
    }
    if(low[u]==dfn[u]) {
        ++scc;
        for(;;) {
            int x=S.top();
            S.pop();
            id[x]=scc;
            vis[x]=-1;
            if(x==u) {
                break;
            }
        }
    }
}
int main() {
    // setIO("broadcast");
    int i,j;
    scanf("%d",&n);
    tot=n;
    int tp=0;
    int root=0;
    for(i=1;i<=n;++i) {
        scanf("%d%d",&X[i],&con[i]);
        L[i]=X[i]-con[i];
        R[i]=X[i]+con[i];
        A[++tp]=X[i];
        A[++tp]=L[i];
        A[++tp]=R[i];
    }
    sort(A+1,A+1+tp);
    for(i=1;i<=n;++i) {
        X[i]=lower_bound(A+1,A+1+tp,X[i])-A;
        L[i]=lower_bound(A+1,A+1+tp,L[i])-A;
        R[i]=lower_bound(A+1,A+1+tp,R[i])-A;
    }
    for(i=1;i<=n;++i) {
        update(root,1,inf,i);
    }
    build(root);
    for(i=1;i<=n;++i) {
        Add(root,1,inf,L[i],R[i],i);
    }
    for(i=1;i<=n;++i) {
        if(!vis[i]) {
            tarjan(i);
        }
    }
    for(i=1;i<=tot;++i) {
        for(j=hd[i];j;j=nex[j]) {
            int v=to[j];
            if(!id[i]||!id[v]) {
                continue;
            }
            if(id[v]!=id[i]) {
                ++In[id[v]];
                ++Ou[id[i]];
                G[id[i]].push_back(id[v]);
            }
        }
    }
    for(i=1;i<=n;++i) {
        is[id[i]]=1;
    }
    for(i=1;i<=scc;++i) {
        if(!In[i]) {
            q.push(i);
        }
    }
    while(!q.empty()) {
        int u=q.front();
        q.pop();
        for(int i=0;i<G[u].size();++i) {
            int v=G[u][i];
            --In[v];
            tag[v]|=(tag[u]|is[u]);
            if(!In[v]) {
                q.push(v);
            }
        }
    }
    int a1=0;
    int a2=0;
    for(i=1;i<=scc;++i) {
        if(is[i]) {
            ++a1;
        }
    }
    for(i=1;i<=scc;++i) {
        if(!tag[i]&&is[i]) {
            ++a2;
        }
    }
    printf("%d %d\n",a2,a1);
    return 0;
}

  

原文地址:https://www.cnblogs.com/guangheli/p/12075814.html

时间: 2024-10-08 18:52:26

模拟赛T2 线段树优化建图+tarjan+拓扑排序的相关文章

bzoj5017 [Snoi2017]炸弹 (线段树优化建图+)tarjan 缩点+拓扑排序

题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=5017 题解 这个题目方法挺多的. 线段树优化建图 线段树优化建图的做法应该挺显然的,一个炸弹能够引爆的炸弹的显然应该是一个区间里面的,直接对这个区间进行线段树优化建图. 这样可以得到一个带环图,缩点以后这个炸弹能够炸到的炸弹就是从这个点能够走到的点. 但是这个不太好做,不过可以发现最终的炸弹也是一个区间,所以可以通过缩点后的 DAG 来求出左右端点. 时间复杂度 \(O(n\log n)\)

【2019北京集训2】duck 线段树优化建图+tarjan

题目大意:给你$n$个点,第$i$个点有点权$v_i$.你需要将这$n$个点排成一排,第$i$个点的点权能被累加当且仅当这个点前面存在编号在$[l_i,r_i]$中的点,问你这些点应该如何排列,点权和才能最大. 数据范围:$n≤10^5$,$1≤v_i≤10^4$. 这题状压居然给了70分,场上压根没想正解. 我们不难发现,对于点i,我们连接$l_i→i$,$(l_i+1)→i$,....,$r_i→i$的边,然后跑一个tarjan,缩点后我们得到了一棵树. 对于每棵树,我们显然只需要减去这棵树

【bzoj4276】[ONTAK2015]Bajtman i Okr?g?y Robin 线段树优化建图+费用流

题目描述 有n个强盗,其中第i个强盗会在[a[i],a[i]+1],[a[i]+1,a[i]+2],...,[b[i]-1,b[i]]这么多段长度为1时间中选出一个时间进行抢劫,并计划抢走c[i]元.作为保安,你在每一段长度为1的时间内最多只能制止一个强盗,那么你最多可以挽回多少损失呢? 输入 第一行包含一个正整数n(1<=n<=5000),表示强盗的个数. 接下来n行,每行包含三个正整数a[i],b[i],c[i](1<=a[i]<b[i]<=5000,1<=c[i]

【bzoj3073】[Pa2011]Journeys 线段树优化建图+堆优化Dijkstra

题目描述 Seter建造了一个很大的星球,他准备建造N个国家和无数双向道路.N个国家很快建造好了,用1..N编号,但是他发现道路实在太多了,他要一条条建简直是不可能的!于是他以如下方式建造道路:(a,b),(c,d)表示,对于任意两个国家x,y,如果a<=x<=b,c<=y<=d,那么在xy之间建造一条道路.Seter保证不会有一个国家与自己之间有道路. Seter好不容易建好了所有道路,他现在在位于P号的首都.Seter想知道P号国家到任意一个国家最少需要经过几条道路.当然,Se

【BZOJ3681】Arietta 树链剖分+可持久化线段树优化建图+网络流

[BZOJ3681]Arietta Description Arietta 的命运与她的妹妹不同,在她的妹妹已经走进学院的时候,她仍然留在山村中.但是她从未停止过和恋人 Velding 的书信往来.一天,她准备去探访他.对着窗外的阳光,临行前她再次弹起了琴.她的琴的发声十分特殊.让我们给一个形式化的定义吧.所有的 n 个音符形成一棵由音符 C ( 1 号节点) 构成的有根树,每一个音符有一个音高 Hi .Arietta 有 m 个力度,第 i 个力度能弹出 Di 节点的子树中,音高在 [Li,R

【ARC069F】Flags 2-sat+线段树优化建图+二分

Description ? 数轴上有 n 个旗子,第 ii 个可以插在坐标 xi或者 yi,最大化两两旗子之间的最小距离. Input ? 第一行一个整数 N. ? 接下来 N 行每行两个整数 xi,yi Output ? 一个整数表示答案. Sample Input Sample #1 3 1 3 2 5 1 9 Sample #2 5 2 2 2 2 2 2 2 2 2 2 Sample #3 22 93 6440 78 6647 862 11 8306 9689 798 99 801 52

Codeforces 787D. Legacy 线段树优化建图+最短路

output standard output Rick and his co-workers have made a new radioactive formula and a lot of bad guys are after them. So Rick wants to give his legacy to Morty before bad guys catch them. There are n planets in their universe numbered from 1 to n.

一个神秘的oj2587 你猜是不是dp(线段树优化建图)

哇 这难道不是happiness的翻版题嘛? 从\(S\)向一个点连染成白色的收益 从这个点向\(T\)连染成黑色的收益 对于额外的收益,建一个辅助点,跟区间内的每个点连\(inf\),然后向S/T,连流量为收益 这不就结束了吗? 自信写完,提交 woc!!只有40分? #include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath>

机房测试5:reverse(bfs+set 或 线段树优化建图)

题目: 分析: 首先画样例分析一下,会发现如果要求一个位置要多少次翻转,就将这个位置向与它关联的点连边(关联点指的是可能与它值互换的位置),一直连到起点为止,连边的次数即为它所需步数. 所以转换成求单源最短路,因为边权为1,可以用bfs. 但是这道题n的范围很大,刚刚的做法是n*k的,考虑优化. 法1:在建图上优化 题目要求的是区间翻转,所以也对应着相关性质:每个点连边一定是都连的奇数点或偶数点(画图可知),且这些奇数偶数点都对应着一段连续的区间. 如果可以将点向点连边优化成点向区间连边,复杂度