zoukankan      html  css  js  c++  java
  • 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
    ",ans[i]);
        return 0;
    }
    View Code

    之前的平衡树启发式合并。

    #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
    ",ans[i]);
        return 0;
    }
    View Code

    还有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
    ",query(root[L[x]-1],root[R[x]],1,n,k));
            else puts("-1");
        }
        return 0;
    }
    View Code
  • 相关阅读:
    C# XmlSerializer实现序列化浅析(转载)
    Direct3D学习(资料收集)
    幸福法则
    javascript中的keydown事件中的参数问题
    去除UTF8 BOM【转】
    JavaScript常用资料参考
    KCFinder CKEditor的文件管理器插件
    elFinder Web文件管理器
    用TcpTrace调试Web服务器
    Ubuntu 12.04如何登入root?
  • 原文地址:https://www.cnblogs.com/wzj-is-a-juruo/p/4828661.html
Copyright © 2011-2022 走看看