SPOJ COT2 - Count on a tree II(樹上莫隊)
題目描述
給定一個n個節點的樹,每個節點表示一個整數,問u到v的路徑上有多少個不同的整數。
輸入格式
第一行有兩個整數n和m(n=40000,m=100000)。
第二行有n個整數。第i個整數表示第i個節點表示的整數。
在接下來的n-1行中,每行包含兩個整數u v,描述一條邊(u,v)。
在接下來的m行中,每一行包含兩個整數u v,詢問u到v的路徑上有多少個不同的整數。
輸出格式
對於每個詢問,輸出結果。 貢獻者:つるまる
題目描述
You are given a tree with N nodes. The tree nodes are numbered from 1 to N. Each node has an integer weight.
We will ask you to perform the following operation:
- u v : ask for how many different integers that represent the weight of nodes there are on the path from u to v.
輸入輸出格式
輸入格式:
In the first line there are two integers N and M. (N <= 40000, M <= 100000)
In the second line there are N integers. The i-th integer denotes the weight of the i-th node.
In the next N-1 lines, each line contains two integers u v, which describes an edge (u, v).
In the next M lines, each line contains two integers u v, which means an operation asking for how many different integers that represent the weight of nodes there are on the path from u to v.
輸出格式:
For each operation, print its result.
輸入輸出樣例
輸入樣例#1: 復制8 2 105 2 9 3 8 5 7 7 1 2 1 3 1 4 3 5 3 6 3 7 4 8 2 5 7 8輸出樣例#1: 復制
4 4
SDOI 2018因為沒學過樹上莫隊慘遭爆零,
不過這玩意兒確實定好玩的。
首先建出歐拉序來,然後對於每個詢問,分兩種情況討論。
這裏就不展開講了,
#include<cstdio> #include<cmath> #include<algorithm> #include<vector> //#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin),p1==p2)?EOF:*p1++) char buf[1 << 21], *p1 = buf, *p2 = buf; using namespace std; const int MAXN = 1e5 + 10; inline int read() { char c = getchar(); int x = 0, f = 1; while(c < ‘0‘ || c > ‘9‘) {if(c == ‘-‘) f = -1; c = getchar();} while(c >= ‘0‘ && c <= ‘9‘) x = x * 10 + c - ‘0‘, c = getchar(); return x * f; } int N, Q; int belong[MAXN], block; struct Query { int l, r, ID, lca, ans; bool operator < (const Query &rhs) const{ return belong[l] == belong[rhs.l] ? r < rhs.r : belong[l] < belong[rhs.l]; // return belong[l] < belong[rhs.l]; } }q[MAXN]; vector<int>v[MAXN]; int a[MAXN], date[MAXN]; void Discretization() { sort(date + 1, date + N + 1); int num = unique(date + 1, date + N + 1) - date - 1; for(int i = 1; i <= N; i++) a[i] = lower_bound(date + 1, date + num + 1, a[i]) - date; } int deep[MAXN], top[MAXN], fa[MAXN], siz[MAXN], son[MAXN], st[MAXN], ed[MAXN], pot[MAXN], tot; void dfs1(int x, int _fa) { fa[x] = _fa; siz[x] = 1; st[x] = ++ tot; pot[tot] = x; for(int i = 0; i < v[x].size(); i++) { int to = v[x][i]; if(deep[to]) continue; deep[to] = deep[x] + 1; dfs1(to, x); siz[x] += siz[to]; if(siz[to] > siz[son[x]]) son[x] = to; } ed[x] = ++tot; pot[tot] = x; } void dfs2(int x, int topfa) { top[x] = topfa; if(!son[x]) return ; dfs2(son[x], topfa); for(int i = 0; i < v[x].size(); i++) { int to = v[x][i]; if(top[to]) continue; dfs2(to, to); } } int GetLca(int x, int y) { while(top[x] != top[y]) { if(deep[top[x]] < deep[top[y]]) swap(x, y); x = fa[top[x]]; } return deep[x] < deep[y] ? x : y; } void DealAsk() { for(int i = 1; i <= Q; i++) { int x = read(), y = read(); if(st[x] > st[y]) swap(x, y); int _lca = GetLca(x, y); q[i].ID = i; if(_lca == x) q[i].l = st[x], q[i]. r = st[y]; else q[i].l = ed[x], q[i].r = st[y], q[i].lca = _lca; } } int Ans, out[MAXN], used[MAXN], happen[MAXN]; void add(int x) { if(++happen[x] == 1) Ans++; } void delet(int x) { if(--happen[x] == 0) Ans--; } void Add(int x) { used[x] ? delet(a[x]) : add(a[x]); used[x] ^= 1; } void Mo() { sort(q + 1, q + Q + 1); int l = 1, r = 0, fuck = 0; for(int i = 1; i <= Q; i++) { while(l < q[i].l) Add(pot[l]), l++, fuck++; while(l > q[i].l) l--, Add(pot[l]), fuck++; while(r < q[i].r) r++, Add(pot[r]), fuck++; while(r > q[i].r) Add(pot[r]), r--, fuck++; if(q[i].lca) Add(q[i].lca); q[i].ans = Ans; if(q[i].lca) Add(q[i].lca); } for(int i = 1; i <= Q; i++) out[q[i].ID] = q[i].ans; for(int i = 1; i <= Q; i++) printf("%d\n", out[i]); } int main() { N = read(); Q = read(); //block = 1.5 * sqrt(2 * N) + 1; //block = pow(N, 0.66666666666); block = sqrt(N); for(int i = 1; i <= N; i++) a[i] = date[i] = read(); for(int i = 1; i <= N * 2; i++) belong[i] = i / block + 1; Discretization(); for(int i = 1; i <= N - 1; i++) { int x = read(), y = read(); v[x].push_back(y); v[y].push_back(x); } deep[1] = 1; dfs1(1, 0); dfs2(1, 1); /* for(int i = 1; i <= N; i++) for(int j = 1; j <= i - 1; j++) printf("%d %d %d\n", i, j, GetLca(i, j));*/ DealAsk(); Mo(); return 0; }
SPOJ COT2 - Count on a tree II(樹上莫隊)