[USACO17JAN] Promotion Counting P 题解
[USACO17JAN] Promotion Counting P 题解
前言
好久没写题解了,今天趁我心情好赶紧水一篇。
思路
首先拿到这题,关键词检索:子树,比
当然,暴力去贡献复杂度肯定爆炸,这里考虑如何通过保留最多的信息来达到减少复杂度的目的。这里用了 DSU on Tree 的思想:保留重儿子的信息,而在递归完轻儿子后清空轻儿子的信息。每个点被再次遍历到,当且仅当它所在的子树大小翻倍。这样做复杂度是
代码:
#include<bits/stdc++.h> using namespace std; const int N = 1e5+100; int read() { int x = 0; char ch = getchar(); while(ch<'0' || ch>'9') ch = getchar(); while(ch>='0'&&ch<='9') x = x*10+(ch-48), ch = getchar(); return x; } int n; int lsh[N], a[N]; //dsu on tree? int head[N], tot; struct node { int nxt, to; } edge[N<<1]; void add(int u, int v) { edge[++tot].nxt = head[u]; edge[tot].to = v; head[u] = tot; } struct BIT { int tc[N]; int lowbit(int x) { return x & (-x); } void insert(int pos, int val) { // printf("%d %d\n", pos, val); for(int i = pos; i<=n; i+=lowbit(i)) { tc[i]+=val; } } int query(int pos) { int ret = 0; for(int i = pos; i; i-=lowbit(i)) { ret+=tc[i]; } return ret; } }bt; int siz[N], son[N]; void predfs(int u, int fath) { siz[u] = 1; for(int i = head[u]; i; i = edge[i].nxt) { int v = edge[i].to; if(v == fath) continue; predfs(v, u); siz[u]+=siz[v]; if(siz[son[u]] < siz[v]) son[u] = v; } } int ans[N]; void pls(int u, int fath) { bt.insert(a[u], 1); for(int i = head[u]; i; i = edge[i].nxt) { int v = edge[i].to; if(v == fath) continue; pls(v, u); } } void del(int u, int fath) { bt.insert(a[u], -1); for(int i = head[u]; i; i = edge[i].nxt) { int v = edge[i].to; if(v == fath) continue; del(v, u); } } void dfs(int u, int fath, bool op) { for(int i = head[u], v; i; i = edge[i].nxt) { v = edge[i].to; if(v == fath || v == son[u]) continue; dfs(v, u, 1); } if(son[u]) dfs(son[u], u, 0); for(int i = head[u], v; i; i = edge[i].nxt) { v = edge[i].to; if(v == fath || v == son[u]) continue; pls(v, u); } ans[u] = bt.query(n) - bt.query(a[u]); bt.insert(a[u], 1); // cout << u << " " << bt.query(n) << " " << bt.query(a[u]) << endl; if(op) del(u, fath); } int main() { n = read(); for(int i = 1; i<=n; ++i) { a[i] = lsh[i] = read(); } sort(lsh+1, lsh+n+1); for(int i = 1; i<=n; ++i) { a[i] = lower_bound(lsh+1, lsh+n+1, a[i])-lsh; } for(int i = 2; i<=n; ++i) { int u = read(); add(u, i); add(i, u); } predfs(1, 0); dfs(1, 0, 0); for(int i = 1; i<=n; ++i) { printf("%d\n", ans[i]); } return 0; }
后记:
后来翻题解发现自己完全是搞麻烦了。其实这个题在递归前后做个差就好……麻了。
完全不会捏 🤡👈😂
分类:
题解
标签:
树状数组
, DSU on Tree