WZJ的数据结构(十三) |
难度级别:D; 运行时间限制:1000ms; 运行空间限制:262144KB; 代码长度限制:2000000B |
试题描述 |
给你一棵N个节点的有根树(根节点为1),每个节点有权值Vi。请回答Q个问题: 每次给你两个正整数x、k,请回答以x为根的子树(包括x节点)中第k小的权值是多少(若不存在第k小数,输出-1)? |
输入 |
第一行为两个正整数N,Q。 接下来N-1行每行两个正整数ui、vi,表示有条从ui向vi的树边。 第N+1行为N个正整数Vi。 最后Q行每行两个正整数x、k。 |
输出 |
对于每次询问输出答案,若不存在第k小数,输出-1。 |
输入示例 |
6 12 1 2 1 3 2 4 3 6 3 5 1 2 1 3 2 1 1 5 2 2 3 4 1 1 1 2 1 3 1 4 1 6 3 3 3 2 5 1 6 1 |
输出示例 |
2 3 -1 1 1 1 2 3 2 1 2 1 |
其他说明 |
1<=N,M,Vi<=100000 1<=x,k<=N |
新学了线段树的合并,来try一发。
#include<cstdio> #include<cctype> #include<queue> #include<cmath> #include<cstring> #include<algorithm> #define rep(i,s,t) for(int i=s;i<=t;i++) #define dwn(i,s,t) for(int i=s;i>=t;i--) #define ren for(int i=first[x];i;i=next[i]) using namespace std; inline int read() { int x=0,f=1;char c=getchar(); for(;!isdigit(c);c=getchar()) if(c==‘-‘) f=-1; for(;isdigit(c);c=getchar()) x=x*10+c-‘0‘; return x*f; } const int maxn=100010; const int maxnode=2000010; int first[maxn],next[maxn<<1],to[maxn<<1],last[maxn],n,q,e,cnt; void AddEdge(int u,int v) { to[++e]=v;next[e]=first[u];first[u]=e; to[++e]=u;next[e]=first[v];first[v]=e; } int ls[maxnode],rs[maxnode],sumv[maxnode],ToT; void update(int& x,int l,int r,int pos) { sumv[x=++ToT]=1;if(l==r) return; int mid=l+r>>1; if(pos<=mid) update(ls[x],l,mid,pos); else update(rs[x],mid+1,r,pos); } int merge(int x,int y) { if(!x||!y) return max(x,y); if(!ls[x]&&!rs[x]) sumv[x]+=sumv[y]; else { ls[x]=merge(ls[x],ls[y]);rs[x]=merge(rs[x],rs[y]); sumv[x]=sumv[ls[x]]+sumv[rs[x]]; } return x; } int query(int x,int l,int r,int k) { if(sumv[x]<k) return -1; if(l==r) return l; int mid=l+r>>1,k2=sumv[ls[x]]; if(k2>=k) return query(ls[x],l,mid,k); return query(rs[x],mid+1,r,k-k2); } struct Query { int k,next,id; }Q[maxn]; int ans[maxn],root[maxn],val[maxn]; void AddQuery(int k,int x,int id) { Q[++cnt]=(Query){k,last[x],id};last[x]=cnt; } void dfs(int x,int fa) { update(root[x],1,100000,val[x]); ren if(to[i]!=fa) { dfs(to[i],x); root[x]=merge(root[x],root[to[i]]); } for(int i=last[x];i;i=Q[i].next) ans[Q[i].id]=query(root[x],1,100000,Q[i].k); } int main() { n=read();q=read(); rep(i,2,n) AddEdge(read(),read()); rep(i,1,n) val[i]=read(); rep(i,1,q) AddQuery(read(),read(),i); dfs(1,0); rep(i,1,q) printf("%d\n",ans[i]); return 0; }
之前的平衡树启发式合并。
#include<cstdio> #include<cstring> #include<queue> #include<cstdlib> #include<ctime> #include<algorithm> using namespace std; const int maxn=100010; struct Node { int r,s,v; Node* ch[2]; void maintain() { s=ch[0]->s+ch[1]->s+1; } }*null=new Node(),nodes[maxn*2]; int tot; queue<Node*> Q; Node* node() { if(!Q.empty()) { Node* o=Q.front(); Q.pop(); return o; } return &nodes[tot++]; } void del(Node* &o) { Q.push(o); o=null; } void rotate(Node* &o,int d) { Node* k=o->ch[d^1]; o->ch[d^1]=k->ch[d]; k->ch[d]=o; o->maintain(); k->maintain(); o=k; } void insert(Node* &o,int v) { if(o==null) { o=node(); o->ch[0]=o->ch[1]=null; o->r=rand(); o->s=1; o->v=v; } else { int d=v>o->v; insert(o->ch[d],v); if(o->ch[d]->r>o->r) rotate(o,d^1); else o->maintain(); } } void remove(Node* &o,int v) { if(v==o->v) { if(o->ch[0]!=null&&o->ch[1]!=null) { int d=o->ch[0]->r>o->ch[1]->r; rotate(o,d); remove(o->ch[d],v); } else { Node* k=o; if(o->ch[0]!=null) o=o->ch[0]; else o=o->ch[1]; del(k); } } else remove(o->ch[v>o->v],v); } int query(Node* &o,int k) { if(k>o->s) return -1; if(k==o->ch[0]->s+1) return o->v; if(k<=o->ch[0]->s) return query(o->ch[0],k); return query(o->ch[1],k-o->ch[0]->s-1); } void print(Node* &o) { if(o==null) return; print(o->ch[0]); printf("%d ",o->v); print(o->ch[1]); } void merge(Node* &big,Node* &sm) { if(sm==null) return; merge(big,sm->ch[0]); merge(big,sm->ch[1]); insert(big,sm->v); del(sm); } Node* root[maxn]; int n,m; int first[maxn],next[maxn*2],to[maxn*2]; void AddEdge(int a,int b) { to[++m]=b; next[m]=first[a]; first[a]=m; } int First[maxn],Next[maxn],K[maxn],ans[maxn],Id[maxn]; void addquery(int x,int k,int id) { K[++m]=k; Id[m]=id; Next[m]=First[x]; First[x]=m; } void dfs(int x,int fa) { for(int i=first[x];i;i=next[i]) { if(to[i]!=fa) { dfs(to[i],x); if(root[x]->s<root[to[i]]->s) swap(root[x],root[to[i]]); merge(root[x],root[to[i]]); } } for(int i=First[x];i;i=Next[i]) ans[Id[i]]=query(root[x],K[i]); } int main() { int Q,a,b; scanf("%d%d",&n,&Q); for(int i=1;i<n;i++) { scanf("%d%d",&a,&b); AddEdge(a,b); AddEdge(b,a); } for(int i=1;i<=n;i++) { root[i]=node(); root[i]->s=1; root[i]->ch[0]=root[i]->ch[1]=null; scanf("%d",&root[i]->v); } m=0; for(int i=1;i<=Q;i++) { scanf("%d%d",&a,&b); addquery(a,b,i); } dfs(1,0); for(int i=1;i<=Q;i++) printf("%d\n",ans[i]); return 0; }
还有DFS序+主席树的version。
#include<cstdio> #include<cctype> #include<cstring> #include<algorithm> using namespace std; inline int read() { char ch=getchar();int sig=1,x=0; while(!isdigit(ch)) {if(ch==‘-‘) sig=-1;ch=getchar();} while(isdigit(ch)) x=x*10+ch-‘0‘,ch=getchar(); return x*sig; } const int maxn=100010; const int maxnode=20000010; int s[maxnode],ls[maxnode],rs[maxnode],ToT; void update(int& y,int x,int l,int r,int pos) { s[y=++ToT]=s[x]+1;if(l==r) return; ls[y]=ls[x];rs[y]=rs[x];int mid=l+r>>1; if(pos<=mid) update(ls[y],ls[x],l,mid,pos); else update(rs[y],rs[x],mid+1,r,pos); } int query(int x,int y,int l,int r,int k) { if(l==r) return l; int mid=l+r>>1; if(s[ls[y]]-s[ls[x]]>=k) return query(ls[x],ls[y],l,mid,k); return query(rs[x],rs[y],mid+1,r,k-s[ls[y]]+s[ls[x]]); } int to[maxn*2],next[maxn*2],first[maxn],e; void AddEdge(int a,int b) { to[++e]=b;next[e]=first[a];first[a]=e; to[++e]=a;next[e]=first[b];first[b]=e; } int L[maxn],R[maxn],v[maxn],root[maxn],pos[maxn],ts,siz[maxn]; void dfs(int x,int fa) { L[x]=++ts;pos[ts]=x;siz[x]=1; for(int i=first[x];i;i=next[i]) if(fa!=to[i]) dfs(to[i],x),siz[x]+=siz[to[i]]; R[x]=ts; } int main() { int n=read(),q=read(),x,k; for(int i=1;i<n;i++) AddEdge(read(),read()); for(int i=1;i<=n;i++) v[i]=read(); dfs(1,0); for(int i=1;i<=n;i++) update(root[i],root[i-1],1,n,v[pos[i]]); while(q--) { x=read();k=read(); if(siz[x]>=k) printf("%d\n",query(root[L[x]-1],root[R[x]],1,n,k)); else puts("-1"); } return 0; }
时间: 2024-09-30 16:24:21