給定一棵n個節點的樹,每個點有乙個權值,對於m個詢問(u,v,k),你需要回答u xor lastans和v這兩個節點間第k小的點權。其中lastans是上乙個詢問的答案,初始為0,即第乙個詢問的u是明文。
第一行兩個整數n,m。
第二行有n個整數,其中第i個整數表示點i的權值。
後面n-1行每行兩個整數(x,y),表示點x到點y有一條邊。
最後m行每行兩個整數(u,v,k),表示一組詢問。
m行,表示每個詢問的答案。最後乙個詢問不輸出換行符
8 5105 2 9 3 8 5 7 7
1 21 3
1 43 5
3 63 7
4 82 5 1
0 5 2
10 5 3
11 5 4
110 8 228
9105
7 n,m<=100000
暴力自重。。。
思路分析 :還是利用主席樹,在樹上建立主席樹,從根節點到當前節點建立線段樹,借助 lca, 然後比如要查詢 u, v 這段區間,要先找到u, v 之間的公共祖先 lca
**示例 :
#define ll long longconst int maxn = 1e5+5;
const int mod = 1e9+7;
const double eps = 1e-9;
const double pi = acos(-1.0);
const int inf = 0x3f3f3f3f;
int n, m;
int pre[maxn], rank[maxn];
vectorve[maxn];
int dep[maxn];
int grand[maxn][22];
int root[maxn];
int cnt, ss;
struct node
t[maxn*20];
void update(int num, int &rt, int l, int r)
void dfs(int x, int fa)
int num = lower_bound(rank+1, rank+ss, pre[x])-rank;
root[x] = root[fa];
update(num, root[x], 1, n);
for(int i = 0; i < ve[x].size(); i++)
}void init()
int getlca(int u, int v)
if (u == v) return u;
for(int i = 20; i >= 0; i--)
}return grand[u][0];
}int query(int t1, int t2, int t3, int t4, int k, int l, int r)
int last=0;
int main()
sort(rank+1, rank+1+n);
ss = unique(rank+1, rank+1+n)-rank;
int a, b;
for(int i = 1; i < n; i++)
dep[1] = 1;
init();
dfs(1, 0);
int u, v, k;
for(int i = 1; i <= m; i++)
return 0;
}
SPOJ COT 樹上第K大 LCA 主席樹
這題和普通的第k大類似。普通的第k大,是從後往前建立主席樹,前乙個在後乙個的基礎上修改。而樹上第k大,依舊是每個結點一棵主席樹,是在父節點的基礎上修改。那麼可以發現這棵主席樹是包括所有祖先結點的 就是深度在當前結點之上的 查詢的時候,是兩個結點的值的和,還要減掉lca以上的部分。同時要注意處理lca...
區間第k大(主席樹)
學了一下主席樹模板題,當初看了網上的主席樹講解都沒有看懂,後面看了嗶哩嗶哩的uestc的主席樹,終於看懂了思想。每次更新的複雜度都為logn。每次更新的話就是對要更新的點路徑上的點重新更加乙個,然後進行對沒有影響的那些進行連邊。然後用乙個root記錄每乙個線段樹的根節點下標。include incl...
主席樹區間第K大
主席樹的實質其實還是一顆線段樹,然後每一次修改都通過上一次的線段樹,來新增新邊,使得每次改變就改變logn個節點,很多節點重複利用,達到節省空間的目的。1.不帶修改的區間第k大。hdu 2665 模板題 1 include2 using namespace std 3 define fopen fr...