bzoj 2588 Count on a tree 解題報告
阿新 • • 發佈:2018-07-31
怎麽 輸出 for 報告 work top code sta rst ,表示一組詢問。
Count on a tree
題目描述
給定一棵\(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\)行,表示每個詢問的答案。
一看是無修改的第\(k\)值查詢,我們可以用可持久化降維。
就是把序列上的第\(k\)值擴展到了樹上。
我們考慮一條樹上路徑可以被怎麽表示
這樣類比,假設樹上每個點有點權,則樹上路徑點權之和可以被樹的前綴和數組這樣表示
\(len(u,v)=dis[u]+dis[v]-dis[lca(u,v)]-dis[father(lca[u,v])]\)
然而前綴和其實就是一維的可持久化,我們把\(dis\)數組類比成主席樹加加減減就好了
Code:
#include <cstdio> #include <algorithm> #define ls ch[now][0] #define rs ch[now][1] const int N=100010; int Next[N<<1],to[N<<1],head[N],cnt; void add(int u,int v) { Next[++cnt]=head[u];to[cnt]=v;head[u]=cnt; } int sum[N*25],ch[N*25][2],tot,n,m,n_; void updata(int now) { sum[now]=sum[ls]+sum[rs]; } int rebuild(int las,int l,int r,int pos) { int now=++tot; if(l==r) { sum[now]=sum[las]+1; return now; } int mid=l+r>>1; if(pos<=mid) { ls=rebuild(ch[las][0],l,mid,pos); rs=ch[las][1]; } else { ls=ch[las][0]; rs=rebuild(ch[las][1],mid+1,r,pos); } updata(now); return now; } int ha[N],loc[N],root[N]; int query(int u,int v,int lca,int lcaf,int l,int r,int k) { if(l==r) return ha[l]; int s=sum[ch[u][0]]+sum[ch[v][0]]-sum[ch[lca][0]]-sum[ch[lcaf][0]]; int mid=l+r>>1; if(k<=s) return query(ch[u][0],ch[v][0],ch[lca][0],ch[lcaf][0],l,mid,k); else return query(ch[u][1],ch[v][1],ch[lca][1],ch[lcaf][1],mid+1,r,k-s); } int top[N],dfn[N],f[N],dep[N],ws[N],siz[N],time; void dfs1(int now) { root[now]=rebuild(root[f[now]],1,n,loc[now]); siz[now]++; for(int i=head[now];i;i=Next[i]) { int v=to[i]; if(v!=f[now]) { f[v]=now; dep[v]=dep[now]+1; dfs1(v); siz[now]+=siz[v]; if(siz[ws[now]]<siz[v]) ws[now]=v; } } } void dfs2(int now,int anc) { dfn[now]=++time; top[now]=anc; if(ws[now]) dfs2(ws[now],anc); for(int i=head[now];i;i=Next[i]) if(!dfn[to[i]]) dfs2(to[i],to[i]); } int LCA(int x,int y) { while(top[x]!=top[y]) { if(dep[top[x]]>dep[top[y]]) x=f[top[x]]; else y=f[top[y]]; } return dep[x]<dep[y]?x:y; } std::pair <int,int > node[N]; void init() { scanf("%d%d",&n_,&m); for(int d,i=1;i<=n_;i++) { scanf("%d",&d); node[i]=std::make_pair(d,i); } std::sort(node+1,node+1+n_); for(int i=1;i<=n_;i++) { if(node[i].first!=node[i-1].first) n++; ha[n]=node[i].first; loc[node[i].second]=n; } for(int u,v,i=1;i<n_;i++) { scanf("%d%d",&u,&v); add(u,v),add(v,u); } dfs1(1); dfs2(1,1); } void work() { for(int u,v,lca,k,lastans=0,i=1;i<=m;i++) { scanf("%d%d%d",&u,&v,&k); u^=lastans; lca=LCA(u,v); printf("%d\n",lastans=query(root[u],root[v],root[lca],root[f[lca]],1,n,k)); } } int main() { init(); work(); return 0; }
2018.7.31
bzoj 2588 Count on a tree 解題報告