Count on a tree
生活随笔
收集整理的這篇文章主要介紹了
Count on a tree
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
bzoj ?2588: Spoj 10628. Count on a tree
http://www.lydsy.com/JudgeOnline/problem.php?id=2588Description
給定一棵N個節點的樹,每個點有一個權值,對于M個詢問(u,v,k),你需要回答u xor lastans和v這兩個節點間第K小的點權。其中lastans是上一個詢問的答案,初始為0,即第一個詢問的u是明文。Input
第一行兩個整數N,M。 第二行有N個整數,其中第i個整數表示點i的權值。 后面N-1行每行兩個整數(x,y),表示點x到點y有一條邊。 最后M行每行兩個整數(u,v,k),表示一組詢問。Output
M行,表示每個詢問的答案。最后一個詢問不輸出換行符
Sample Input
8 5105 2 9 3 8 5 7 7
1 2
1 3
1 4
3 5
3 6
3 7
4 8
2 5 1
0 5 2
10 5 3
11 5 4
110 8 2
Sample Output
28
9
105
7
HINT
HINT:N,M<=100000
暴力自重。。。
Source
鳴謝seter
數據結構:主席樹
輔助算法:LCA
以點的dfs序為下標,以點權為區間建立主席樹
以前做過的主席樹在序列上,所以是以前一個節點的線段樹為基準建立的
這里在樹上,所以可以考慮以根為基準建立線段樹
u,v間增加的點數=cnt[u]+cnt[v]-cnt[LCA(u,v)]-cnt[father[LCA(u,v)]]
#include<cstdio> #include<algorithm> #define N 100001 using namespace std; struct count {private:struct node{int l,r,cnt;}tr[N*20];struct data {int to,next;}e[N*2];int n,m,a[N],head[N],edge_cnt;int dep[N],son[N],f[N],bl[N],sz;int root[N],cntt,hash[N],hash_tot;int last;public:inline int read(){int x=0,f=1;char c=getchar();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;}inline void add(int u,int v){e[++edge_cnt].to=v;e[edge_cnt].next=head[u];head[u]=edge_cnt;e[++edge_cnt].to=u;e[edge_cnt].next=head[v];head[v]=edge_cnt;}void init(){n=read();m=read();for(int i=1;i<=n;i++) a[i]=read(),hash[i]=a[i];int u,v;for(int i=1;i<n;i++){scanf("%d%d",&u,&v);add(u,v);}}inline void tree_insert(int pre,int & now,int l,int r,int k){tr[now=++cntt].cnt=tr[pre].cnt+1;if(l==r) return;int mid=l+r>>1;if(k<=mid) {tr[now].r=tr[pre].r;tree_insert(tr[pre].l,tr[now].l,l,mid,k);}else {tr[now].l=tr[pre].l;tree_insert(tr[pre].r,tr[now].r,mid+1,r,k); }}inline void dfs1(int x,int fa) {son[x]++;tree_insert(root[fa],root[x],1,hash_tot,hash[x]); for(int i=head[x];i;i=e[i].next){if(e[i].to==fa) continue;f[e[i].to]=x;dep[e[i].to]=dep[x]+1;dfs1(e[i].to,x);son[x]+=son[e[i].to];}}inline void dfs2(int x,int chain)//給重鏈編號 {bl[x]=chain;int m=0;for(int i=head[x];i;i=e[i].next){if(e[i].to==f[x]) continue;if(son[e[i].to]>son[m]) m=e[i].to;}if(!m) return;dfs2(m,chain);for(int i=head[x];i;i=e[i].next){if(e[i].to==f[x]||e[i].to==m) continue;dfs2(e[i].to,e[i].to);} }inline int getlca(int u,int v)//求lca,本函數+上面2個函數為樹鏈剖分求LCA {while(bl[u]!=bl[v]){if(dep[bl[u]]<dep[bl[v]]) swap(u,v);u=f[bl[u]];}if(dep[u]<dep[v]) return u;return v;}void discrete(){sort(a+1,a+n+1);hash_tot=unique(a+1,a+n+1)-(a+1);for(int i=1;i<=n;i++) hash[i]=lower_bound(a+1,a+hash_tot+1,hash[i])-a;}inline int tree_query(int x,int y,int lca,int fa_lca,int l,int r,int k){if(l==r) return a[l];int mid=l+r>>1,tmp=tr[tr[x].l].cnt+tr[tr[y].l].cnt-tr[tr[lca].l].cnt-tr[tr[fa_lca].l].cnt;if(k<=tmp) tree_query(tr[x].l,tr[y].l,tr[lca].l,tr[fa_lca].l,l,mid,k);else tree_query(tr[x].r,tr[y].r,tr[lca].r,tr[fa_lca].r,mid+1,r,k-tmp);}void init2(){int u,v,k;for(int i=1;i<=m;i++){u=read();v=read();k=read();u^=last;int lca=getlca(u,v);last=tree_query(root[u],root[v],root[lca],root[f[lca]],1,hash_tot,k);if(i!=m )printf("%d\n",last);else printf("%d",last);}}void work(){init();discrete();dfs1(1,0);dfs2(1,1);init2();}}a; int main() {a.work(); }初做犯了一個很蠢的錯誤:最后一行不輸出換行,楞是沒看見
不讀完題,第二次了。
轉載于:https://www.cnblogs.com/TheRoadToTheGold/p/6383854.html
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的Count on a tree的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux 各文件系统配置
- 下一篇: BZOJ2843:极地旅行社