제출 #850711

#제출 시각아이디문제언어결과실행 시간메모리
850711danikoynovTourism (JOI23_tourism)C++14
100 / 100
410 ms49744 KiB
/**
 ____ ____ ____ ____ ____ ____
||l |||e |||i |||n |||a |||d ||
||__|||__|||__|||__|||__|||__||
|/__\|/__\|/__\|/__\|/__\|/__\|

**/

#include<bits/stdc++.h>
#define endl '\n'

using namespace std;
typedef long long ll;

void speed()
{
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);
}

const int maxn = 1e5 + 10;

struct query
{
    int l, r, idx;
} task[maxn];

int n, m, c[maxn], q;
vector < int > adj[maxn];

void input()
{
    cin >> n >> m >> q;
    for (int i = 1; i < n; i ++)
    {
        int v, u;
        cin >> v >> u;
        adj[v].push_back(u);
        adj[u].push_back(v);
    }

    for (int i = 1; i <= m; i ++)
    {
        cin >> c[i];
    }

    for (int i = 1; i <= q; i ++)
    {
        cin >> task[i].l >> task[i].r;
        task[i].idx = i;
    }
}


int depth[maxn], tin[maxn], tout[maxn];
int occ[2 * maxn], rev[2 * maxn], timer;
int sub[maxn], heavy[maxn];

void euler(int v = 1, int p = - 1)
{
    occ[++ timer] = v;
    tin[v] = timer;
    rev[timer] = v;
    sub[v] = 1;
    heavy[v] = -1;
    for (int u : adj[v])
    {
        if (u == p)
            continue;
        depth[u] = depth[v] + 1;
        euler(u, v);
        if (heavy[v] == -1 || sub[u] > sub[heavy[v]])
            heavy[v] = u;
        sub[v] += sub[u];
        occ[++ timer] = v;
    }
    tout[v] = timer;
}

const int maxlog = 20;

int lg[2 * maxn], dp[maxlog][2 * maxn];

void sparse_table()
{
    for (int i = 1; i <= timer; i ++)
    {
        lg[i] = lg[i / 2] + 1;
        dp[0][i] = occ[i];
    }

    for (int j = 1; j < lg[timer]; j ++)
        for (int i = 1; i <= timer - (1 << j); i ++)
        {
            dp[j][i] = dp[j - 1][i + (1 << (j - 1))];
            if (depth[dp[j - 1][i]] < depth[dp[j][i]])
                dp[j][i] = dp[j - 1][i];
        }
}

int get_lca(int v, int u)
{
    int l = tin[v], r = tin[u];
    if (l > r)
        swap(l, r);
    int len = lg[r - l + 1] - 1;
    int lca = dp[len][r - (1 << len) + 1];
    if (depth[dp[len][l]] < depth[lca])
        lca = dp[len][l];
    return lca;
}

int get_distance(int v, int u)
{
    return depth[v] + depth[u] - 2 * depth[get_lca(v, u)];
}

struct interval
{
    int left, right, value;

    interval(int _left = 0, int _right = 0, int _value = 0)
    {
        left = _left;
        right = _right;
        value = _value;
    }
    bool operator < (const interval seg) const
    {
        if (left == seg.left)
        {
            if (value == seg.value)
                assert(right == seg.right);
            /// values cannot be the same
            return value > seg.value;

        }
        else
            return left < seg.left;
    }
};
struct chain
{
    int top, left, right;


    set < interval > act;
} st[maxn];

int ch_idx[maxn], ch_cnt, ord[maxn], last, ch_pos[maxn];

void hld(int v = 1, int p = -1)
{
    ///cout << v << " : " << p << endl;
    ch_idx[v] = ch_cnt;
    ord[++ last] = v;
    ch_pos[v] = last;
    st[ch_idx[v]].right = last;
    if (heavy[v] != -1)
        hld(heavy[v], v);
    for (int u : adj[v])
    {
        if (u == p || u == heavy[v])
            continue;
        ch_cnt ++;
        st[ch_cnt].top = v;
        st[ch_cnt].left = last + 1;
        st[ch_cnt].right = last + 1;
        hld(u, v);
    }
}

void decompose()
{
    ch_idx[1] = 1;
    ch_cnt = 1;
    ch_pos[1] = 1;
    st[ch_cnt].left = st[ch_cnt].right = 1;
    st[ch_cnt].top = 0;
    hld();

    /**cout << ch_cnt << endl;
    for (int i = 1; i <= ch_cnt; i ++)
        cout << st[i].left << " " << st[i].right << endl;
    for (int i = 1; i <= n; i ++)
    cout << ord[i] << " ";
    cout << endl;*/
}

int fen[maxn];

void update(int v, int val)
{
    for (int i = v; i <= m; i += (i & -i))
        fen[i] += val;
}

int query_sum(int v)
{
    int s = 0;
    for (int i = v; i > 0; i -= (i & -i))
        s += fen[i];
    return s;
}

int col[maxn];
void write_on_chain(int idx, int left, int right, int val)
{
    /**for (int i = left; i <= right; i ++)
    {
        if (col[i] != 0)
            update(col[i], - 1);
        col[i] = val;
    }*/
    ///update(val, right - left + 1);
    ///return;
    interval seg(left, right, val);


    st[idx].act.insert(seg);
    set < interval > :: iterator it, bef, aft;
    it = st[idx].act.find(seg);
    update(val, right - left + 1);
    ///cout << "write on chain " << val << " " << left << " " << right << endl;
    if (it != st[idx].act.begin())
    {
        bef = prev(it);

        if (bef -> right >= right)
        {
            update(bef -> value, - (right - left + 1));
            interval lf_split(bef -> left, left - 1, bef -> value);
            interval rf_split(right + 1, bef -> right, bef -> value);
            st[idx].act.erase(bef);
            if (lf_split.left <= lf_split.right)
                st[idx].act.insert(lf_split);
            if (rf_split.left <= rf_split.right)
                st[idx].act.insert(rf_split);
        }
        else if (bef -> right >= left)
        {

            update(bef -> value, - (bef -> right - left + 1));

            interval new_bef(bef -> left, left - 1, bef -> value);
            st[idx].act.erase(bef);
            if (new_bef.left <= new_bef.right)
                st[idx].act.insert(new_bef);
        }
    }

    while(true)
    {

        it = st[idx].act.find(seg);
        if (next(it) != st[idx].act.end())
        {
            aft = next(it);
            if (aft -> right <= right)
            {
                update(aft -> value, - (aft -> right - aft -> left + 1));
                st[idx].act.erase(aft);
                continue;
            }
            if (aft -> left <= right)
            {
                update(aft -> value, - (right - aft -> left + 1));
                interval new_aft(right + 1, aft -> right, aft -> value);
                st[idx].act.erase(aft);
                if (new_aft.left <= new_aft.right)
                    st[idx].act.insert(new_aft);
            }
            break;
        }
        else
            break;


    }

    /**if (idx != 25)
        return;
    cout << "writing " << idx << endl;
    cout << "add " << left << " " << right << endl;
        for (interval cur : st[idx].act)
    {

        cout << cur.left << " " << cur.right << " " << cur.value << endl;
    }
    for (interval cur : st[idx].act)
    {
        for (int j  = cur.left; j <= cur.right; j ++)
        {
            if (col[j] != cur.value)
            {
                cout <<" wtf " << endl;
                //exit(0);
            }
        }

    }*/
}

void write_on_path(int v, int p, int val)
{
    ///cout << "write on path " << v << " " << p << endl;
    while(ch_idx[v] != ch_idx[p])
    {
        write_on_chain(ch_idx[v], st[ch_idx[v]].left, ch_pos[v], val);
        v = st[ch_idx[v]].top;
    }


    if (ch_pos[p] < ch_pos[v])
        write_on_chain(ch_idx[v], ch_pos[p] + 1, ch_pos[v], val);

}


vector < query > ask[maxn];
int res[maxn];
void queries()
{

    ///q = 1;
    for (int i = 1; i <= q; i ++)
        ask[task[i].l].push_back(task[i]);

    for (int i = m; i > 0; i --)
    {
        if (i != m)
        {
            int v = c[i], u = c[i + 1];
            int lca = get_lca(v, u);
            write_on_path(v, lca, i);
            write_on_path(u, lca, i);
        }
        /**cout << "step " << i << endl;
        for (int j = 1; j <= m; j ++)
            cout << query_sum(j) - query_sum(j - 1) << " ";
        cout << endl;*/
        for (query cur : ask[i])
        {
            res[cur.idx] = query_sum(cur.r - 1) + 1;
        }
    }


    for (int i = 1; i <= q; i ++)
        cout << res[i] << endl;
}

void solve()
{
    input();
    euler();
    sparse_table();
    decompose();
    queries();

}

int main()
{
    ///freopen("test.txt", "r", stdin);
    speed();
    solve();
    return 0;
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...