[T3] 2019.7.26 NOIP simulation game chemical reaction (Reaction) (FIG segment tree construction optimized condensing point + + Tarjan topological sort)

Transformed the meaning of problems

We have to consider the side, then for each point, the answer is that it can reach for each build a relationship between the activation points.

So, the problem was we moved on the map, it has become a topic map.

Optimization of Construction Plan

We need to consider a range connected to one side of each section.

Then we can use to optimize the construction segment tree diagram .

It is the specific steps, to build two segment tree, each time a new dummy node, then the need to connect the outward side of the section to the tree nodes attached to an edge line segment, and from this tree node to the other one segment even it should be connected side edge sections.

Solving answer

After the completion of the construction drawing, consider how to find the answer.

First, we \ (Tarjan \) all nodes condensing points, apparently within a strongly connected component can reach each other.

Second, we can find a node can reach range must be a contiguous range.

We then, for each strongly connected component, wherein the maintenance interval can reach the node.

Then topological sorting, can be transferred.

Code

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 200000
#define M 50000
#define LN 20
#define X 1000000007
#define Gmin(x,y) (x>(y)&&(x=(y)))
#define Gmax(x,y) (x<(y)&&(x=(y)))
using namespace std;
int n,m;struct Reaction {int l1,r1,l2,r2;}s[M+5];
class FastIO
{
    private:
        #define FS 100000
        #define tc() (A==B&&(B=(A=FI)+fread(FI,1,FS,stdin),A==B)?EOF:*A++)
        #define tn (x<<3)+(x<<1)
        #define D isdigit(c=tc())
        char c,*A,*B,FI[FS];
    public:
        I FastIO() {A=B=FI;}
        Tp I void read(Ty& x) {x=0;W(!D);W(x=tn+(c&15),D);}
        Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
}F;
class GraphSolver//将问题搬到图上求解
{
    private:
        #define P (N<<3)+M//点数
        #define E (N<<3)+(M*LN<<2)//边数
        template<int PS,int ES> class Graph//一张图
        {
            private:
                int ee;
            public:
                int n,lnk[PS+5];struct edge {int to,nxt;}e[ES+5];I Graph() {n=1;}
                I void add(CI x,CI y) {Gmax(n,x),Gmax(n,y),e[++ee].nxt=lnk[x],e[lnk[x]=ee].to=y;}//建边
        };
        template<int SZ,int PS,int ES> class SegmentTreeGraphBuilder//线段树优化建图
        {
            private:
                #define L l,mid,S[rt][0]
                #define R mid+1,r,S[rt][1]
                int n,tot,rtI,rtO,S[SZ<<3][2];
                I void BuildI(CI l,CI r,int& rt)//初始化入边线段树
                {
                    if(l==r) return (void)(rt=l);rt=++tot;RI mid=l+r>>1;
                    BuildI(L),BuildI(R),G.add(rt,S[rt][0]),G.add(rt,S[rt][1]);//由父亲向儿子连边
                }
                I void BuildO(CI l,CI r,int& rt)//初始化出边线段树
                {
                    if(l==r) return (void)(rt=l);rt=++tot;RI mid=l+r>>1;
                    BuildO(L),BuildO(R),G.add(S[rt][0],rt),G.add(S[rt][1],rt);//由儿子向父亲连边
                }
                I void LinkI(CI tx,CI tl,CI tr,CI l,CI r,CI rt)//在入边线段树上连边
                {
                    if(tl<=l&&r<=tr) return G.add(tx,rt);RI mid=l+r>>1;
                    tl<=mid&&(LinkI(tx,tl,tr,L),0),tr>mid&&(LinkI(tx,tl,tr,R),0);
                }
                I void LinkO(CI tx,CI tl,CI tr,CI l,CI r,CI rt)//在出边线段树上连边
                {
                    if(tl<=l&&r<=tr) return G.add(rt,tx);RI mid=l+r>>1;
                    tl<=mid&&(LinkO(tx,tl,tr,L),0),tr>mid&&(LinkO(tx,tl,tr,R),0);
                }
            public:
                Graph<PS,ES> G;I void Build(CI _n) {tot=n=_n,BuildI(1,n,rtI),BuildO(1,n,rtO);}//初始化
                I void Link(CI l1,CI r1,CI l2,CI r2) {++tot,LinkO(tot,l1,r1,1,n,rtO),LinkI(tot,l2,r2,1,n,rtI);}//区间向区间连边
        };
        template<int PS,int ES> class Tarjaner//Tarjan缩点建新图
        {
            private:
                int n,d,T,dfn[PS+5],low[PS+5],vis[PS+5],S[PS+5],col[PS+5];
                I void Tarjan(CI lim,Con Graph<PS,ES>& G,CI x,CI lst=0)//Tarjan
                {
                    RI i;dfn[x]=low[x]=++d,vis[S[++T]=x]=1;
                    for(i=G.lnk[x];i;i=G.e[i].nxt)
                        dfn[G.e[i].to]?vis[G.e[i].to]&&Gmin(low[x],dfn[G.e[i].to])
                        :(Tarjan(lim,G,G.e[i].to,x),Gmin(low[x],low[G.e[i].to]));
                    if(low[x]^dfn[x]) return;col[x]=++n,Mn[n]=x,Mx[n]=x<=lim?x:0,vis[x]=0;
                    W(x^S[T]) col[S[T]]=n,Gmin(Mn[n],S[T]),S[T]<=lim&&Gmax(Mx[n],S[T]),vis[S[T--]]=0;--T;
                }
            public:
                int Mn[PS+5],Mx[PS+5];Graph<PS,ES> nG;I int operator [] (CI x) {return col[x];}
                I void ReBuild(CI lim,Con Graph<PS,ES>& G)//重构建新图
                {
                    RI i,j;for(i=1;i<=G.n;++i) !dfn[i]&&(Tarjan(lim,G,i),0);
                    for(i=1;i<=G.n;++i) for(j=G.lnk[i];j;j=G.e[j].nxt)
                        col[i]^col[G.e[j].to]&&(nG.add(col[i],col[G.e[j].to]),0);//连边
                }
        };
        template<int PS,int ES> class Topoer//拓扑排序求解答案
        {
            private:
                int q[PS+5],deg[PS+5],fl[PS+5],fr[PS+5];
            public:
                I int operator [] (CI x) {return fr[x]-fl[x]+1;}
                I void Work(int *Mn,int *Mx,Con Graph<PS,ES>& G)
                {
                    RI i,j,k,H=1,T=0;
                    for(i=1;i<=G.n;++i) for(j=G.lnk[i];j;j=G.e[j].nxt) ++deg[G.e[j].to];
                    for(i=1;i<=G.n;++i) !deg[i]&&(q[++T]=i);W(H<=T)//拓扑排序
                        for(i=G.lnk[k=q[H++]];i;i=G.e[i].nxt) !--deg[G.e[i].to]&&(q[++T]=G.e[i].to);
                    for(i=T;i;--i)//倒过来转移
                    {
                        fl[q[i]]=Mn[q[i]],fr[q[i]]=Mx[q[i]];
                        for(j=G.lnk[q[i]];j;j=G.e[j].nxt) Gmin(fl[q[i]],fl[G.e[j].to]),Gmax(fr[q[i]],fr[G.e[j].to]);//维护每个强连通分量所能到达的区间
                    }
                }
        };
        SegmentTreeGraphBuilder<N,P,E> S;Tarjaner<P,E> T;Topoer<P,E> O;
    public:
        I void Solve()
        {
            RI i,ans=0;for(S.Build(n),i=1;i<=m;++i) S.Link(s[i].l1,s[i].r1,s[i].l2,s[i].r2);//建边
            for(T.ReBuild(n,S.G),O.Work(T.Mn,T.Mx,T.nG),i=1;i<=n;++i) ans=(1LL*i*O[T[i]]+ans)%X;//求解,计算答案
            printf("%d",ans);//输出答案
        }
}S;
int main()
{
    freopen("reaction.in","r",stdin),freopen("reaction.out","w",stdout);
    RI i;for(F.read(n,m),i=1;i<=m;++i) F.read(s[i].l1,s[i].r1,s[i].l2,s[i].r2);
    return S.Solve(),0;
}

Guess you like

Origin www.cnblogs.com/chenxiaoran666/p/Contest20190726T3.html