「YNOI2016自身の発明

「YNOI2016自身の発明

ルートを変更しないでください

基本Moのチーム、それ...

DFS順に直接サブツリー。

残りは見ることができる「SNOI2017」単純問い合わせを

他のルートで

三種類に分けルートルート、クエリのx、:

  1. Xは、DFSができ、元の配列間隔に応じて、サブツリーのルートでありません
  2. サブツリー内のx根と根!= X、その後、シーケンス全体がHの除去である(ルート祖先、及びxは息子である)、DFSに対応する配列部
  3. ルート= xで

その上に直接シーケンス拡散、一定の総\(SQRT 2 \ \ 8)

最適化

場合Hに対応する間隔\([L、R] \ ) 答えが\(CNT [1、L 1] + CNT [R + 1、N] =(CNT [1、N] -cnt [L 、R])\) その後、別のセクションに取ります。

これは、アウト前処理することができる\([1、X] \ ) と\([1、N] \ ) 回答。

従って、各質問は一度だけ行う([L、R] \ \ ) と\([L1、R1] \ ) クエリの、4定数。

しかし、ではない実際にはあまり速く...


2E6の問い合わせのソートは、複雑さが非常に高いです。

したがって、各メモリブロックは、Vector、リオーダリングと尋問の左端に相当します。

効果は、(明らかです!


乗算プロセスは、各点について、除去することができる点ジャンプ点のサブツリー二点で直接その時点で息子、場合に、子DFNベクター配列が格納されています。

少しだけ速く...

#include <bits/stdc++.h>
#define rep(q, a, b) for (int q = a, q##_end_ = b; q <= q##_end_; ++q)
#define dep(q, a, b) for (int q = a, q##_end_ = b; q >= q##_end_; --q)
#define mem(a, b) memset(a, b, sizeof a)
#define debug(a) cerr << #a << ' ' << a << "___" << endl
using namespace std;
bool cur1;
char buf[10000000], *p1 = buf, *p2 = buf;
#define Getchar() p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 10000000, stdin), p1 == p2) ? EOF : *p1++
void in(int &r) {
    static char c;
    r = 0;
    while (c = Getchar(), c < 48)
        ;
    do
        r = (r << 1) + (r << 3) + (c ^ 48);
    while (c = Getchar(), c > 47);
}

const int mn = 100005;
const int mm = 500005;
int K, n, m, vl[mn], val[mn];
int head[mn], ne[mn << 1], to[mn << 1], cnt2;
#define link(a, b) link_edge(a, b), link_edge(b, a)
#define link_edge(a, b) to[++cnt2] = b, ne[cnt2] = head[a], head[a] = cnt2
#define travel(x) for (int q(head[x]); q; q = ne[q])
int ind, dfn_l[mn], dfn_r[mn];
vector<int> son[mn];
int mp[mn];
void dfs(int f, int x) {
    ++ind, mp[ind]=x,val[ind] = vl[x], dfn_l[x] = ind;
    travel(x) if (to[q] != f) dfs(x, to[q]),son[x].push_back(dfn_l[to[q]]);
    dfn_r[x] = ind;
}
int get_high(int x, int v) {
    int l=0,r=(int)son[x].size()-1,ans=0;
    while(l<=r){
        int mid=l+r>>1;
        if(son[x][mid]>v)r=mid-1;
        else l=mid+1,ans=mid;
    }
    return mp[son[x][ans]];
}
long long ans[mm];
struct node {
    int l, r, id;
    inline bool operator<(const node &A) const { return r < A.r; }
};
inline bool cmp(node a, node b) { return a.r > b.r; }
vector<node> an[800];
int cnt[mn], cnt1[mn];
bool mark[mm];
long long mid_ans, mid[mn];
void init() {
    dfs(0, 1);

    sort(mid + 1, mid + n + 1);
    rep(q, 1, n) val[q] = lower_bound(mid + 1, mid + n + 1, val[q]) - mid;

    rep(q, 1, n)++ cnt[val[q]];
    rep(q, 1, n) mid[q] = mid[q - 1] + cnt[val[q]];
    rep(q, 1, n)-- cnt[val[q]];
}
int find(int rt, int x) {
    if (dfn_l[rt] >= dfn_l[x] && dfn_l[rt] <= dfn_r[x])
        return get_high(x, dfn_l[rt]);
    return 0;
}
bool cur2;
int main() {
    //  cerr<<(&cur2-&cur1)/1024.0/1024<<endl;
    int td, l, r, l1, r1;
    in(n), in(m);
    rep(q, 1, n) in(vl[q]), mid[q] = vl[q];
    rep(q, 2, n) in(l), in(r), link(l, r);
    init();
    K = n / sqrt(m)*1.2 + 1;
    int rt = 1;
    rep(q, 1, m) {
        in(td);
        if (td == 1)
            in(rt);
        else {
            mark[q] = 1;
            in(l), in(l1);
            if (rt == l || rt == l1) {
                if (rt == l1)
                    swap(l, l1);
                if (rt == l1)
                    ans[q] = mid[n];
                else {
                    int at = find(rt, l1);
                    if (at)
                        ans[q] = mid[n] - (mid[dfn_r[at]] - mid[dfn_l[at] - 1]);
                    else
                        ans[q] = mid[dfn_r[l1]] - mid[dfn_l[l1] - 1];
                }
            } else {
                int at = find(rt, l), at1 = find(rt, l1);
                if (!at)
                    swap(at, at1), swap(l, l1);
                td = 1;
                if (at && !at1)
                    ans[q] = mid[dfn_r[l1]] - mid[dfn_l[l1] - 1], td = -1, l = at;
                else if (at1)
                    ans[q] = mid[n] - (mid[dfn_r[at]] - mid[dfn_l[at] - 1]) -
                             (mid[dfn_r[at1]] - mid[dfn_l[at1] - 1]),
                    l = at, l1 = at1;
                r = dfn_r[l], l = dfn_l[l];
                r1 = dfn_r[l1], l1 = dfn_l[l1];
                an[r / K].push_back({ r, r1, q * td });
                if (l > 1) {
                    an[min(r1, l - 1) / K].push_back({ min(r1, (l - 1)), max(r1, (l - 1)), -q * td });
                    if (l1 > 1)
                        an[min(l - 1, l1 - 1) / K].push_back(
                            { min(l - 1, l1 - 1), max(l - 1, l1 - 1), q * td });
                }
                if (l1 > 1)
                    an[min(r, l1 - 1) / K].push_back({ min(r, l1 - 1), max(r, l1 - 1), -q * td });
            }
        }
    }
    l = 0, r = 0;
    rep(q, 0, n / K) {
        if (q & 1)
            sort(an[q].begin(), an[q].end(), cmp);
        else
            sort(an[q].begin(), an[q].end());
        rep(w, 0, (int)an[q].size() - 1) {
            l1 = an[q][w].l, r1 = an[q][w].r;
            while (l > l1) mid_ans -= cnt1[val[l]], --cnt[val[l--]];
            while (r < r1) mid_ans += cnt[val[++r]], ++cnt1[val[r]];
            while (l < l1) mid_ans += cnt1[val[++l]], ++cnt[val[l]];
            while (r > r1) mid_ans -= cnt[val[r]], --cnt1[val[r--]];
            an[q][w].id < 0 ? ans[-an[q][w].id] -= mid_ans : ans[an[q][w].id] += mid_ans;
        }
    }
    rep(q, 1, m) if (mark[q]) printf("%lld\n", ans[q]);
    return 0;
}

おすすめ

転載: www.cnblogs.com/klauralee/p/10948945.html