hdu5709 Claris Loves Painting
阿新 • • 發佈:2020-08-03
給一棵 n 點的樹,每個節點上有一個顏色 \(c_i\) ,q 次詢問一個點的子樹中與這個點距離不
超過 d 的點的顏色有多少種。
(強制線上)
考慮開兩棵線段樹
第一棵中的每個點維護這個點的子樹內深度在\([l,r]\)之間有多少個點
第二棵的每個點維護這個點的子樹內每種顏色的最小深度
我們從葉子節點向上合併,先合併第一棵再合併第二棵,如果合併第二棵時有兩個顏色相等的節點,就保留深度小的並在第一棵線段樹裡減去這個點的貢獻
Code
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> const int N = 5e5; using namespace std; int T,n,m,c[N + 5],f[N + 5],dep[N + 5],rt1[N + 5],rt2[N + 5],node_cnt,val[N * 40 + 5],lc[N * 40 + 5],rc[N * 40 + 5]; inline int read() { int X(0),w(0);char ch(0); while (!isdigit(ch))w|=ch=='-',ch=getchar(); while (isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar(); return w?-X:X; } void insert(int &k,int las,int l,int r,int x,int v) { k = ++node_cnt; val[k] = val[las] + v; lc[k] = lc[las]; rc[k] = rc[las]; if (l == r) return; int mid = l + r >> 1; if (x <= mid) insert(lc[k],lc[las],l,mid,x,v); else insert(rc[k],rc[las],mid + 1,r,x,v); } int merge1(int x,int y) { if (!x || !y) return x + y; int z = ++node_cnt; val[z] = val[x] + val[y]; lc[z] = merge1(lc[x],lc[y]); rc[z] = merge1(rc[x],rc[y]); return z; } int merge2(int x,int y,int l,int r,int k) { if (!x || !y) return x + y; int z = ++node_cnt; if (l == r) { val[z] = min(val[x],val[y]); if (val[x] < val[y]) insert(rt1[k],rt1[k],1,n,val[y],-1); else insert(rt1[k],rt1[k],1,n,val[x],-1); return z; } int mid = l + r >> 1; lc[z] = merge2(lc[x],lc[y],l,mid,k); rc[z] = merge2(rc[x],rc[y],mid + 1,r,k); return z; } int query(int k,int l,int r,int x) { if (!k) return 0; if (r <= x) return val[k]; int mid = l + r >> 1; if (x <= mid) return query(lc[k],l,mid,x); else return query(lc[k],l,mid,x) + query(rc[k],mid + 1,r,x); } int main() { T = read(); while (T--) { n = read(); m = read(); for (int i = 1;i <= n;i++) c[i] = read(); dep[1] = 1; for (int i = 2;i <= n;i++) f[i] = read(),dep[i] = dep[f[i]] + 1; for (int i = 1;i <= n;i++) { insert(rt1[i],0,1,n,dep[i],1); insert(rt2[i],0,1,n,c[i],dep[i]); } for (int i = n;i >= 2;i--) { rt1[f[i]] = merge1(rt1[i],rt1[f[i]]); rt2[f[i]] = merge2(rt2[i],rt2[f[i]],1,n,f[i]); } int ans = 0; int x,d; while (m--) { x = read(); d = read(); x ^= ans; d ^= ans; d = min(n,d + dep[x]); ans = query(rt1[x],1,n,d); printf("%d\n",ans); } ans = node_cnt = 0; } return 0; }