列表

详情


NC25526. 图上计数

描述

给定一棵以 1 为根,大小为 N 的树,每个点有若干条出边,如果你要 的话,它们需要按照输入的顺序去遍历(就是指定了 序)
你需要维护一种数据结构,支持两种操作:
1 x:将 x 为根的子树中的节点,以 序为下标,编号大小为关键字排序。相当于树的形态不变,但是子树里节点的编号排了遍序, 序小的对应编号小的, 序大的对应编号大的
2 x:查询原先树中点 x 现在的编号是多少
一共会给出 Q 个询问。

输入描述

第一行两个整数 N,Q
之后有 N 行,第 i+1 行的第一个数 k_i 表示节点 i 有 k_i 个儿子,之后有 k_i 个数,表示这些儿子
之后有 Q 行,每行诸如1 x或者2 x

输出描述

对于每一个询问操作,输出一行一个整数

示例1

输入:

5 6
2 2 3
2 4 5
0
0
0
1 1
2 1
2 2
2 3
2 4
2 5

输出:

1
2
5
3
4

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++14(g++5.4) 解法, 执行用时: 179ms, 内存消耗: 27620K, 提交时间: 2019-05-11 20:52:59

#include "bits/stdc++.h"
using namespace std;
const int N = 1e5 + 10;
int n, m;
vector<int> g[N];
int dfn[N], clk, pos[N], sz[N];
void dfs(int u) {
    dfn[++clk] = u, pos[u] = clk, sz[u] = 1;
    for (int i = 0; i < g[u].size(); ++i) {
        int v = g[u][i];
        dfs(v);
        sz[u] += sz[v];
    }
    // printf("sz[%d] = %d\n", u, sz[u]);
}
int fa[N];
int get(int x) { return x == fa[x] ? x : fa[x] = get(fa[x]); }

void modify(int u, int acc) {
    if (fa[u])
        return fa[get(u)] = get(acc), void();
    else
        fa[u] = u, fa[get(u)] = get(acc);

    for (int i = 0; i < g[u].size(); ++i) {
        int v = g[u][i];
        modify(v, acc);
    }
}
int root[N], sum[N * 20], lc[N * 20], rc[N * 20], tot;
void modify(int &last, int now, int l, int r, int pos) {
    lc[now] = lc[last], rc[now] = rc[last], sum[now] = sum[last] + 1;
    if (l == r)
        return;
    int mid = (l + r) >> 1;
    if (pos <= mid)
        modify(lc[last], lc[now] = ++tot, l, mid, pos);
    else
        modify(rc[last], rc[now] = ++tot, mid + 1, r, pos);
}
int query(int L, int R, int l, int r, int k) {
    int mid = (l + r) >> 1, s = sum[lc[R]] - sum[lc[L]];
    if (l == r)
        return l;
    if (s >= k)
        return query(lc[L], lc[R], l, mid, k);
    else
        return query(rc[L], rc[R], mid + 1, r, k - s);
}
int query(int u) {
    if (!fa[u])
        return u;
    int f = get(u);
    // printf("f = %d sz = %d query: [%d, %d]: %d\n", f, sz[f], pos[f], pos[f] + sz[f] - 1, pos[u] - pos[f] +
    // 1);
    return query(root[pos[f] - 1], root[pos[f] + sz[f] - 1], 1, n, pos[u] - pos[f] + 1);
}
int main() {
    scanf("%d%d", &n, &m);
    for (int i = 1, k; i <= n; ++i) {
        scanf("%d", &k);
        for (int j = 1, x; j <= k; ++j) {
            scanf("%d", &x);
            g[i].push_back(x);
        }
    }
    dfs(1);
    // for(int i = 1 ; i <= n ; ++ i) cout << dfn[i] << ' '; cout << endl;
    for (int i = 1; i <= n; ++i) {
        // cout << "tot = " << tot << endl;
        modify(root[i - 1], root[i] = ++tot, 1, n, dfn[i]);
    }
    for (int i = 1, op, u; i <= m; ++i) {
        scanf("%d%d", &op, &u);
        if (op == 1) {
            if (!fa[u])
                modify(u, u);
        } else {
            printf("%d\n", query(u));
        }
    }
}

C++(clang++11) 解法, 执行用时: 179ms, 内存消耗: 6212K, 提交时间: 2021-04-03 10:55:24

#include<bits/stdc++.h>

using namespace std;

const int N=1e5+100;

vector<int> g[N]; 
int dfn[N];
int rnk[N];
int siz[N];
int cnt=0;
void dfs(int x){
	siz[x]=1;
	dfn[x]=++cnt;
	rnk[cnt]=x;
	for(int i=0;i<g[x].size();i++){
		int y=g[x][i];
		dfs(y);
		siz[x]+=siz[y];
	}
}

int vis[N];

int main(){
	int n,q;
	cin>>n>>q;
	for(int i=1;i<=n;i++){
		int k;
		cin>>k;
		for(int j=1;j<=k;j++){
			int x;
			cin>>x;
			g[i].push_back(x);
			vis[x]=1;
		}
	}
	int root;
	for(int i=1;i<=n;i++) if(vis[i]==0) root=i;
	dfs(root);
	while(q--){
		int op,x;
		cin>>op>>x;
		if(op==1) {
			sort(rnk+dfn[x],rnk+dfn[x]+siz[x]);
//			for(int i=1;i<=n;i++)
//				cout<<rnk[i]<<" "<<dfn[i]<<endl;
		}
		else printf("%d\n",rnk[dfn[x]]);
	}  
	return 0;
}

上一题