COJ1013 WZJ的数据结构(十三)

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-08-01 15:18:18

COJ1013 WZJ的数据结构(十三)的相关文章

COJ 0967 WZJ的数据结构(负三十三)

WZJ的数据结构(负三十三) 难度级别:E: 运行时间限制:7000ms: 运行空间限制:262144KB: 代码长度限制:2000000B 试题描述 请你设计一个数据结构,完成以下功能: 给定一个大小为N的整数组A,要求你回答执行N次操作.操作分两种: 操作1:每次操作给你l,r,v三个参数,求Al至Ar中值<=v的个数. 操作2:每次操作给你l,r,v三个参数,将Al至Ar所有数的值设为v. 输入 第一行为一个正整数N.第二行为N个整数Ai.接下来N行每行4个正整数t,l,r,v.若t=2表

COJ WZJ的数据结构(负三十三)

WZJ的数据结构(负三十三) 难度级别:E: 运行时间限制:7000ms: 运行空间限制:262144KB: 代码长度限制:2000000B 试题描述 请你设计一个数据结构,完成以下功能: 给定一个大小为N的整数组A,要求你回答执行N次操作.操作分两种: 操作1:每次操作给你l,r,v三个参数,求Al至Ar中值<=v的个数. 操作2:每次操作给你l,r,v三个参数,将Al至Ar所有数的值设为v. 输入 第一行为一个正整数N.第二行为N个整数Ai.接下来N行每行4个正整数t,l,r,v.若t=2表

COJ 0970 WZJ的数据结构(负三十)树分治

WZJ的数据结构(负三十) 难度级别:D: 运行时间限制:1000ms: 运行空间限制:262144KB: 代码长度限制:2000000B 试题描述 给你一棵N个点的无根树,点和边上均有权值.请你设计一个数据结构,回答M次操作. 1 x v:对于树上的每一个节点y,如果将x.y在树上的距离记为d,那么将y节点的权值加上d*v. 2 x:询问节点x的权值. 输入 第一行为一个正整数N.第二行到第N行每行三个正整数ui,vi,wi.表示一条树边从ui到vi,距离为wi.第N+1行为一个正整数M.最后

COJ 0981 WZJ的数据结构(负十九)树综合

WZJ的数据结构(负十九) 难度级别:E: 运行时间限制:15000ms: 运行空间限制:262144KB: 代码长度限制:2000000B 试题描述 WZJ的数据结构中有很多都是关于树的.这让很多练习模板的同学还要找来找去很不爽,于是WZJ跟小伙伴们一块商量如何将这些题汇拢到一块去: WZJ:为了大家简单,我规定一开始是一棵有根树. LZJ:那我一定得加上换根操作喽. XJR:链信息修改,链信息增加,链信息翻倍,维护链信息的最大,最小,总和肯定很好做. CHX:子树信息修改,子树信息增加,子树

COJ 0979 WZJ的数据结构(负二十一)

WZJ的数据结构(负二十一) 难度级别:C: 运行时间限制:5000ms: 运行空间限制:262144KB: 代码长度限制:2000000B 试题描述 请你实现一个数据结构,完成这样的功能: 给你一个N个点的图,初始状态无边. 每次加入一条双向边(u,v,w),若加入后没有构成一棵生成树,输出“Not Yet”,否则输出当前最小生成树的权值. 输入 第一行两个正整数N,M.表示有N个点M个操作.接下来M行每行三个正整数u,v,w. 输出 每次加入一条双向边(u,v,w),若加入后没有构成一棵生成

COJ 1010 WZJ的数据结构(十) 线段树区间操作

传送门:http://oj.cnuschool.org.cn/oj/home/problem.htm?problemID=1001 WZJ的数据结构(十) 难度级别:D: 运行时间限制:3000ms: 运行空间限制:51200KB: 代码长度限制:2000000B 试题描述 请你设计一个数据结构,高效执行以下过程: #include<iostream>using namespace std;const int maxn=100010;int A[maxn];int tp,ql,qr,v;int

COJ 0995 WZJ的数据结构(负五)区间操作

WZJ的数据结构(负五) 难度级别:C: 运行时间限制:1000ms: 运行空间限制:262144KB: 代码长度限制:2000000B 试题描述 请你设计一个数据结构,完成以下功能: 给定一个大小为N的整数组A,要求你回答执行M次操作.操作分两种: 操作1:每次操作给你l,r,v三个参数,求Al至Ar中值<=v的个数. 操作2:每次操作给你l,r,v三个参数,将Al至Ar中每个数的值+v. 输入 第一行为一个正整数N.第二行为N个整数Ai.第三行为一个正整数M.接下来M行每行4个正整数t,l,

COJ 0999 WZJ的数据结构(负一)

WZJ的数据结构(负一) 难度级别:D: 运行时间限制:1000ms: 运行空间限制:262144KB: 代码长度限制:2000000B 试题描述 输入N个模板串Pi和文本串T,输出每个模板串Pi在T中出现了多少次. 输入 第一行为一个正整数N.接下来N行为Pi.最后一行为T 输出 输出N行,第i行为模板串Pi在T中出现的次数. 输入示例 5aabbaabaaababababa 输出示例 54445 其他说明 1<=sigma(|Pi|)<=10000001<=|T|<=10000

COJ 1010 WZJ的数据结构(十) 线段树的地狱

传送门:http://oj.cnuschool.org.cn/oj/home/problem.htm?problemID=1001 WZJ的数据结构(十) 难度级别:D: 运行时间限制:3000ms: 运行空间限制:51200KB: 代码长度限制:2000000B 试题描述 请你设计一个数据结构,高效执行以下过程: #include<iostream>using namespace std;const int maxn=100010;int A[maxn];int tp,ql,qr,v;int