問題の牛オフより学校第フィールドEエクスプローラ(左右開閉セグメントツリー+リトラクタブル互いに素なセット)溶液

質問の意味:

そこ\(N \)ポイントが無向グラフを構成し、それぞれの側には、持っている\(L_iを、R_iとは\)数だけ許可することができ、このエッジを表す\(L_iを\ドットR_iとを\)人によっては、今あなたがほとんどを尋ねます何人か\(1 \)が行ってきました(N- \)\を

アイデア:

私たちは、それぞれの番号を列挙し、この数まで見てみるように、すべてのエッジがマップを形成することができますすることができます\(1 \)が行ってきました\(\ N-を)が、ポイントは、列挙が、その後、我々メダル現実的ではないことは明らかですインターバルのため。
我々は、左及び開閉ツリーラインメンテナンス間隔を、そして、各ノードは、現在の辺の数が範囲をカバーし、次にツリー線を横断することができ格納できるようにする権利。場合、リトラクタブル互いに素なセットの現在のビューを維持する\(1 \)\(N \)同じイトゥリでは、その後明らかにそれから現在の範囲満たすことができる\(1 \)を行ったN(\を\ )、そして貢献を追加します。

コード:

#include<map>
#include<set>
#include<queue>
#include<stack>
#include<ctime>
#include<cmath>
#include<cstdio>
#include<string>
#include<vector>
#include<cstring>
#include<sstream>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 2e5 + 5;
const int INF = 0x3f3f3f3f;
const ull seed = 131;
const ll MOD = 1e9;
using namespace std;
vector<int> node[maxn << 2], vv;
int ans, n, m;
void build(int l, int r, int rt){
    node[rt].clear();
    if(l == r) return;
    int m = (l + r) >> 1;
    build(l, m, rt << 1);
    build(m + 1, r, rt << 1 | 1);
}
void update(int L, int R, int l, int r, int v, int rt){
    if(L <= l && R >= r){
        node[rt].push_back(v);
        return;
    }
    int m = (l + r) >> 1;
    if(L <= m)
        update(L, R, l, m, v, rt << 1);
    if(R > m)
        update(L, R, m + 1, r, v, rt << 1 | 1);
}
struct qu{
    int u, v, l, r;
}q[maxn];
int getid(int x){
    return lower_bound(vv.begin(), vv.end(), x) - vv.begin() + 1;
}

stack<pair<int, int> > instack;    //合并的点和其父节点暂时增加的秩
int fa[maxn], dep[maxn];
int _find(int x){
    return x == fa[x]? x : _find(fa[x]);
}
void Merge(int x, int y){
    int fx = _find(x), fy = _find(y);
    if(dep[fx] < dep[fy]){
        fa[fx] = fy;
        instack.push(make_pair(fx, 0));
    }
    else if(dep[fx] > dep[fy]){
        fa[fy] = fx;
        instack.push(make_pair(fy, 0));
    }
    else{
        fa[fx] = fy;
        dep[fy]++;
        instack.push(make_pair(fx, 1));
    }
}
void undo(){
    pair<int, int> s = instack.top();
    instack.pop();
    dep[fa[s.first]] -= s.second;
    fa[s.first] = s.first;
}
void dfs(int l, int r, int rt){
    for(int i = 0; i < node[rt].size(); i++){
        int u = q[node[rt][i]].u, v = q[node[rt][i]].v;
        Merge(u, v);
    }
    if(_find(1) == _find(n)){
        ans += vv[r] - vv[l - 1];
    }
    else if(l < r){
        int m = (l + r) >> 1;
        dfs(l, m, rt << 1);
        dfs(m + 1, r, rt << 1 | 1);
    }
    for(int i = 0; i < node[rt].size(); i++){
        undo();
    }
}
int main(){
    while(~scanf("%d%d", &n, &m)){
        for(int i = 1; i <= m; i++){
            scanf("%d%d%d%d", &q[i].u, &q[i].v, &q[i].l, &q[i].r);
            vv.push_back(q[i].l), vv.push_back(q[i].r + 1);
        }
        sort(vv.begin(), vv.end());
        vv.erase(unique(vv.begin(), vv.end()), vv.end());

        build(1, vv.size(), 1);
        for(int i = 1; i <= m; i++){
            update(getid(q[i].l), getid(q[i].r + 1) - 1, 1, vv.size(), i, 1);
        }
        for(int i = 0; i <= n; i++) fa[i] = i;
        while(!instack.empty()) instack.pop();
        ans = 0;
        dfs(1, vv.size(), 1);
        printf("%d\n", ans);
    }
    return 0;
}

おすすめ

転載: www.cnblogs.com/KirinSB/p/11391003.html