bzoj 1146 - Network

来源:互联网 发布:ubuntu arm 国内源 编辑:程序博客网 时间:2024/05/16 19:39

昨晚写代码的时候就预料到这次debug要好久。。。果然,下午debug了4个小时,还是sb错误,不能忍,简直就是自己给自己挖了个坑,那么问题来了。。。

树上的区间第k大,树链剖分先做好。查询的时候,比如u到v上的第k大,我们先二分这个第K大的值,再统计u,v路径上的比二分的这个值大的有多少,然后比较;确定u,v上比val大的数目时,可以利用树状数组思想,建立n个treap树,统计树上比这个值大的有多少,具体来说就是num_bigger_than[u]-num_bigger_than[v-1];调整的时候,就要按照树状数组的方法,对每个相关的树去更新。

#include <cstdio>#include <cstdlib>#include <cstring>#include <iostream>using namespace std;const int maxn=80010;//treap beginsstruct Node{    Node *ch[2]; // 左右子树    int r; // 随机优先级    int v; // 值    int s;    Node(int v):v(v)    {        ch[0] = ch[1] = NULL;        r = rand();        s = 1;    }    int cmp(int x) const    {        if (x == v) return -1;        return x < v ? 0 : 1;    }    void maintain()    {        s = 1;        if(ch[0] != NULL) s += ch[0]->s;        if(ch[1] != NULL) s += ch[1]->s;    }};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 x){    if(o == NULL) o = new Node(x);    else    {        int d = (x < o->v ? 0 : 1);        Insert(o->ch[d], x);        if(o->ch[d]->r > o->r) Rotate(o, d^1);    }    o->maintain();}void Remove(Node* &o, int x){    int d = o->cmp(x);    int ret = 0;    if(d == -1)    {        Node* u = o;        if(o->ch[0] != NULL && o->ch[1] != NULL)        {            int d2 = (o->ch[0]->r > o->ch[1]->r ? 1 : 0);            Rotate(o, d2);            Remove(o->ch[d2], x);        }        else        {            if(o->ch[0] == NULL) o = o->ch[1];            else o = o->ch[0];            delete u;        }    }    else        Remove(o->ch[d], x);    if(o != NULL) o->maintain();}int kth(Node *o,int k){    if(o==NULL||k<=0||k>o->s)   return 0;    int s=(o->ch[1]==NULL?0:o->ch[1]->s);    if(k==s+1)  return o->v;    else if(k<=s)    return kth(o->ch[1],k);    else return kth(o->ch[0],k-s-1);}int upper1(const Node *t,int val)  //第t棵树上比val大的有多少{    if(t==NULL) return 0;    int tmp=t->v,res=0;    if(tmp==val)    {        res++;        res+=upper1(t->ch[0],val);        res+=upper1(t->ch[1],val);    }    else if(tmp>val)    {        res++;        if(t->ch[1]!=NULL)            res+=t->ch[1]->s;        res+=upper1(t->ch[0],val);    }    else        res+=upper1(t->ch[1],val);    return res;}Node *root[maxn];//ends,about the questionstruct EdgeNode{    int to,next;} edge[maxn*2];int w[maxn],head[maxn],top[maxn],fa[maxn],    dep[maxn],num[maxn],idx[maxn],son[maxn];int cnt,pos,n;inline void add_edge(int u,int v){    edge[cnt].to=v,edge[cnt].next=head[u];    head[u]=cnt++;    edge[cnt].to=u,edge[cnt].next=head[v];    head[v]=cnt++;}void dfs(int u,int pre,int d){    dep[u]=d,fa[u]=pre,num[u]=1;    for(int k=head[u]; k!=-1; k=edge[k].next)    {        int v=edge[k].to;        if(v==pre)  continue;        dfs(v,u,d+1);        num[u]+=num[v];        if(son[u]==-1||num[v]>num[son[u]])            son[u]=v;    }}void build_tree(int u,int tp){    top[u]=tp,idx[u]=++pos;    if(son[u]==-1)  return;    build_tree(son[u],tp);    for(int k=head[u]; k!=-1; k=edge[k].next)    {        int v=edge[k].to;        if(v!=son[u]&&v!=fa[u])            build_tree(v,v);    }}int lca(int u,int v){    while(top[u]!=top[v])    {        if(dep[top[u]]<dep[top[v]]) swap(u,v);        u=fa[top[u]];    }    if(dep[u]>dep[v])   swap(u,v);    return u;}int gao(int l,int r,int val) //l->r区间上比val大的一共有多少{    int ans=0;    int k=r;    while(k)    {        ans+=upper1(root[k],val);        k-=k&(-k);    }    k=l-1;    while(k)    {        ans-=upper1(root[k],val);        k-=k&(-k);    }    return ans;}void modify(int u,int val){    if(w[u]==val)   return;    int k=idx[u];    while(k<=n)    {        Remove(root[k],w[u]);        Insert(root[k],val);        k+=k&(-k);    }    Remove(root[maxn-1],w[u]);    Insert(root[maxn-1],val);    w[u]=val;}int great(int u,int v,int val) //统计u->v上比val大的一共有多少{    int ql,qr,ans=0;    while(top[u]!=top[v])    {        if(dep[top[u]]<dep[top[v]]) swap(u,v);        ql=idx[top[u]],qr=idx[u];        ans+=gao(ql,qr,val);        u=fa[top[u]];    }    if(dep[u]>dep[v])   swap(u,v);    ans+=gao(idx[u],idx[v],val);    return ans;}int qurey(int u,int v,int k){    int pa=lca(u,v);    if(dep[u]+dep[v]-2*dep[pa]+1<k) return -1;    int l=1,r=n;    while(l<=r)    {        int mid=l+r>>1;        int tmp=kth(root[maxn-1],mid);  //二分val值        if(great(u,v,tmp)>=k)            r=mid-1;        else            l=mid+1;    }    return kth(root[maxn-1],l);}int main(){    int m;    while(scanf("%d%d",&n,&m)!=EOF)    {        cnt=pos=0;        memset(head,-1,sizeof(head));        memset(son,-1,sizeof(son));        for(int i=0; i<maxn; i++) root[i]=NULL;        for(int i=1; i<=n; i++)            scanf("%d",&w[i]);        for(int i=1; i<n; i++)        {            int u,v;            scanf("%d%d",&u,&v);            add_edge(u,v);        }        dfs(1,1,1);        build_tree(1,1);        for(int i=1; i<=n; i++)        {            int p=idx[i];            Insert(root[maxn-1],w[i]);            while(p<=n)            {                Insert(root[p],w[i]);                p+=p&(-p); //树状数组思想            }        }        for(int i=1; i<=m; i++)        {            int k,a,b;            scanf("%d%d%d",&k,&a,&b);            if(!k)  modify(a,b);            else            {                int ans=qurey(a,b,k);                if(ans==-1) printf("invalid request!\n");                else                    printf("%d\n",ans);            }        }    }    return 0;}

0 0
原创粉丝点击