bzoj3720: Gty的妹子树

来源:互联网 发布:商务软件解决方案比赛 编辑:程序博客网 时间:2024/05/01 05:31

题目链接

bzoj3720

题意

维护一棵初始有n个节点的有根树(根节点为1),树上节点编号为1-n,每个点有一个权值wi。
支持以下操作:
0 u x 询问以u为根的子树中,严格大于x的值的个数。(u^=lastans,x^=lastans)
1 u x 把u节点的权值改成x。(u^=lastans,x^=lastans)
2 u x 添加一个编号为”当前树中节点数+1”的节点,其父节点为u,其权值为x。(u^=lastans,x^=lastans)
最开始时lastans=0。(强制在线)
(1<=n<=30000,1<=m<=30000)

题解

与子树相关的问题我们能想到树剖,dfs序等东西。但是这道题要支持加点与大于x数的个数的统计。这样就不是很好做了。
但是注意到修改是单点的,并且n不是非常大。我们可以分块乱搞。
我们先确定一个块的大小S,将树分成若干个联通块,每块的大小都不超过S。
我们在每个块内将权值从小到大排序。
询问时,若在一个整块内,我们二分查找,否则暴力。
修改是暴力维护块内的权值有序。
加点时判断父亲所在块大小是否等于S,等于的话该点单独成一块,否则加入父亲所在块内,注意也要维护块内权值有序。
由于有二分操作,块的大小取nlog2n 最合适。(我也不会证明,但亲测是这样)。


代码:

#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#include<queue>#include<vector>#include<cmath>using namespace std;#define N 60010#define M 60010struct node{    int pos,top,data,fa;}t[N];struct block{    int size;    vector<int>v;}b[M];struct edge{    int x,next;}e[N*2][2];int x,y,n,m,tot[2],num,first[N][2],ans,lim,op;queue<int>q;void add(int x,int y,int k){    e[++tot[k]][k].x=y;    e[tot[k]][k].next=first[x][k];    first[x][k]=tot[k];}void newnode(int x,int top,int pos){    b[pos].v.push_back(t[x].data);    b[pos].size++;    t[x].pos=pos;    t[x].top=top;}void bfs(){    newnode(1,1,++num); q.push(1);    while(!q.empty()){        x=q.front(); q.pop();        for(int i=first[x][0];i;i=e[i][0].next)        if(e[i][0].x!=t[x].fa){            if(b[t[x].pos].size>=lim){                newnode(e[i][0].x,e[i][0].x,++num);                add(t[x].pos,num,1);            }else newnode(e[i][0].x,t[x].top,t[x].pos);            t[e[i][0].x].fa=x;            q.push(e[i][0].x);        }    }}int count(int x,int y){    int l=0,r=b[x].v.size(),mid;    while((r-l)>1){        mid=(l+r)>>1;        if(b[x].v[mid]>y)r=mid;        else l=mid;    }    if(b[x].v[l]>y)r=l;    int tmp=b[x].v.size()-r;    for(int i=first[x][1];i;i=e[i][1].next)    tmp+=count(e[i][1].x,y);    return tmp;}int ask(int x,int y){    if(t[x].top==x)return count(t[x].pos,y);    int tmp=(t[x].data>y);    for(int i=first[x][0];i;i=e[i][0].next)    if(e[i][0].x!=t[x].fa) tmp+=ask(e[i][0].x,y);    return tmp;}void modify(int x,int y){    int p=t[x].pos,n=b[p].v.size(),i;    for(i=0;i<n;i++)    if(b[p].v[i]==t[x].data)break;    t[x].data=b[p].v[i]=y;    for(;i<n-1&&b[p].v[i]>b[p].v[i+1];i++)    swap(b[p].v[i],b[p].v[i+1]);    for(;i>0&&b[p].v[i]<b[p].v[i-1];i--)    swap(b[p].v[i],b[p].v[i-1]);}void insert(int x,int y){    add(x,y,0);    if(b[t[x].pos].size>=lim){        newnode(y,y,++num);        add(t[x].pos,num,1);    }else newnode(y,t[x].top,t[x].pos);    int i=b[t[y].pos].v.size()-1;    for(;i>0&&b[t[y].pos].v[i]<b[t[y].pos].v[i-1];i--)    swap(b[t[y].pos].v[i],b[t[y].pos].v[i-1]);}int main(){    scanf("%d",&n);    for(int i=1;i<n;i++){        scanf("%d%d",&x,&y);        add(x,y,0);        add(y,x,0);    }    for(int i=1;i<=n;i++) scanf("%d",&t[i].data);    lim=(int)sqrt(n)*(log(n)/log(2));    bfs();    for(int i=1;i<=num;i++)sort(b[i].v.begin(),b[i].v.end());    scanf("%d",&m);    for(int i=1;i<=m;i++){        scanf("%d%d%d",&op,&x,&y);        x^=ans; y^=ans;        if(op==0) ans=ask(x,y),printf("%d\n",ans);        else if(op==1)modify(x,y);        else if(op==2) {            t[++n].data=y;            insert(x,n);        }    }    return 0;}
0 0