[luogu P4230]連環病原體

[luogu P4230] 連環病原體

題意

給定一個長度爲 \(n\) 的邊序列, 當這個序列的一個子區間內的邊都加入圖中時產生了環則稱其爲"增強區間", 求序列中的每條邊在多少個增強區間中.c++

\(n\le 4\times 10^5,|V|\le 2\times 10^5\).this

題解

想打休閒板子因而想起了這道上古XCR題...XCR #12好像要咕?spa

首先有一個顯然的沙雕性質: 若是一個子區間是增強區間, 那麼全部包含這個子區間的區間也是增強區間.指針

接着咱們按照套路, 求全部以 \(i\) 爲右端點的增強區間對答案產生的貢獻. 這部分須要快速求.code

根據上面的沙雕性質, 咱們只要求出以 \(i\) 爲右端點的最短增強區間的左端點 \(l\), 那麼全部小於 \(l\) 的左端點也是增強區間. 因而對於全部座標爲 \(k\)\(k<l\) 的位置都會產生 \(k\) 的貢獻, 而對 \(k\in [l,i]\) 則會產生 \(l\) 的貢獻. 因而就變成了區間加等差數列單點求值, 隨手拉個線段樹就能夠搞了.blog

問題變成怎麼求最短增強區間. 不難發現由於有上面的沙雕單調性直接雙指針就能夠了. 可是加邊/刪邊是隨機的, 因此只能用LCT維護.ip

跑得巨快無比. 雖然數據範圍有 \(2\times 10^5\) 個點可是個人常數大如狗的LCT板子極限數據才跑了 \(300\texttt{ms}\)...get

記得當時毒瘤oscar造數據的時候專門卡了查完根不Splay的選手233333it

參考代碼

#include <bits/stdc++.h>

const int MAXN=4e5+10;
typedef long long intEx;

struct LCT{
#define lch chd[0]
#define rch chd[1]
#define kch chd[k]
#define xch chd[k^1]
    struct Node{
        bool rev;
        Node* prt;
        Node* pprt;
        Node* chd[2];
        Node():rev(false),prt(NULL),pprt(NULL),chd{NULL,NULL}{}
        void Flip(){
            if(this!=NULL){
                this->rev=!this->rev;
                std::swap(this->lch,this->rch);
            }
        }
        void PushDown(){
            if(this!=NULL&&this->rev){
                this->lch->Flip();
                this->rch->Flip();
                this->rev=false;
            }
        }
    };
    std::vector<Node*> N;
    LCT(int n):N(n+1){
        for(int i=1;i<=n;i++)
            N[i]=new Node();
    }
    void Rotate(Node* root,int k){
        Node* tmp=root->xch;
        root->PushDown();
        tmp->PushDown();
        tmp->prt=root->prt;
        if(root->prt==NULL){
            tmp->pprt=root->pprt;
            root->pprt=NULL;
        }
        else if(root->prt->lch==root)
            root->prt->lch=tmp;
        else
            root->prt->rch=tmp;
        root->xch=tmp->kch;
        if(root->xch!=NULL)
            root->xch->prt=root;
        tmp->kch=root;
        root->prt=tmp;
    }
    void Splay(Node* root){
        while(root->prt!=NULL){
            int k=root->prt->lch==root;
            if(root->prt->prt==NULL)
                Rotate(root->prt,k);
            else{
                int d=root->prt->prt->lch==root->prt;
                Rotate(k==d?root->prt->prt:root->prt,k);
                Rotate(root->prt,d);
            }
        }
    }
    void Expose(Node* root){
        Splay(root);
        root->PushDown();
        if(root->rch){
            root->rch->pprt=root;
            root->rch->prt=NULL;
            root->rch=NULL;
        }
    }
    bool Splice(Node* root){
        Splay(root);
        if(root->pprt==NULL)
            return false;
        Expose(root->pprt);
        root->pprt->rch=root;
        root->prt=root->pprt;
        root->pprt=NULL;
        return true;
    }
    void Access(Node* root){
        Expose(root);
        while(Splice(root));
    }
    void Evert(Node* root){
        Access(root);
        root->Flip();
    }
    void Link(int a,int b){
        Node* x=N[a];
        Node* y=N[b];
        Evert(y);
        y->pprt=x;
    }
    void Cut(int a,int b){
        Node* x=N[a];
        Node* y=N[b];
        Evert(x);
        Access(y);
        y->PushDown();
        y->lch->prt=NULL;
        y->lch=NULL;
    }
    Node* FindRoot(int x){
        Node* cur=N[x];
        Access(cur);
        while(cur->lch)
            cur=cur->lch;
        Splay(cur);
        return cur;
    }
#undef lch
#undef rch
#undef xch
#undef kch
};

struct Node{
    int l;
    int r;
    intEx add;
    intEx delta;
    Node* lch;
    Node* rch;
    Node(int,int);
    void PushDown();
    intEx Query(int);
    void Add(intEx,intEx);
    void Add(int,int,intEx,intEx);
};

int n;
int v;
std::pair<int,int> E[MAXN];

int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d%d",&E[i].first,&E[i].second);
        v=std::max(E[i].first,v);
        v=std::max(E[i].second,v);
    }
    Node* N=new Node(1,n);
    LCT* T=new LCT(v);
    int l=0;
    for(int i=1;i<=n;i++){
        while(T->FindRoot(E[i].first)==T->FindRoot(E[i].second)){
            ++l;
            T->Cut(E[l].first,E[l].second);
        }
        T->Link(E[i].first,E[i].second);
        if(l!=0){
            N->Add(l+1,i,l,0);
            N->Add(1,l,1,1);
        }
    }
    for(int i=1;i<=n;i++)
        printf("%lld%c",N->Query(i)," \n"[i==n]);
    return 0;
}

inline void Node::PushDown(){
    if(this->add!=0||this->delta!=0){
        this->lch->Add(this->add,this->delta);
        this->rch->Add(this->add+this->delta*(this->rch->l-this->l),this->delta);
        this->add=this->delta=0;
    }
}

inline void Node::Add(intEx a,intEx d){
    if(this!=NULL){
        this->add+=a;
        this->delta+=d;
    }
}

intEx Node::Query(int x){
    if(this->l==this->r)
        return this->add;
    else{
        this->PushDown();
        if(x<=this->lch->r)
            return this->lch->Query(x);
        else
            return this->rch->Query(x);
    }
}

void Node::Add(int l,int r,intEx a,intEx d){
    if(l<=this->l&&this->r<=r)
        this->Add(a+(this->l-l)*d,d);
    else{
        this->PushDown();
        if(l<=this->lch->r)
            this->lch->Add(l,r,a,d);
        if(this->rch->l<=r)
            this->rch->Add(l,r,a,d);
    }
}

Node::Node(int l,int r):l(l),r(r),add(0),delta(0),lch(NULL),rch(NULL){
    if(l!=r){
        int mid=(l+r)>>1;
        this->lch=new Node(l,mid);
        this->rch=new Node(mid+1,r);
    }
}

相關文章
相關標籤/搜索