您的位置:首页 > 其它

bzoj3720 gty的妹子树

2016-01-16 18:35 337 查看

Description

维护一棵初始有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。

Input

输入第一行包括一个正整数n(1<=n<=30000),代表树上的初始节点数。

接下来n-1行,每行2个整数u,v,为树上的一条无向边。

任何时刻,树上的任何权值大于等于0,且两两不同。

接下来1行,包括n个整数wi,表示初始时每个节点的权值。

接下来1行,包括1个整数m(1<=m<=30000),表示操作总数。

接下来m行,每行包括三个整数 op,u,v:

op,u,v的含义见题目描述。

保证题目涉及的所有数在int内。

Output

对每个op=0,输出一行,包括一个整数,意义见题目描述。

块状树

设定每个块的大小上限为sqrt(n),

块内维护块内结点权值的升序排列,并记录由块组成的树

将根结点加入第一个块,对其它结点若父结点所在的块未满就加入其中,否则另开新块

查询时对子树完整包含的块二分查找,不完整的块暴力查找

时间复杂度O(n1.5logn)

#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
int mxsz=200;
vector<int> tr[60005];
vector<int> tr0[60005];
int tp;
int v[60005];
int b[60005];
struct block{
int vs[200],vp;
vector<int>ss;
int id;
block(){
vp=0;
}
void insert(int w);
void change(int a,int b);
int getans(int m);
};
bool isr[60005];
block bs[10005];
int bp=2;
void block::insert(int w){
if(vp<mxsz){
vs[vp++]=v[w];
sort(vs,vs+vp);
b[w]=id;
isr[w]=(vp==1?1:0);
}else{
ss.push_back(bp);
bs[bp++].insert(w);
isr[w]=1;
}
}
void block::change(int a,int b){
for(int i=0;i<vp;i++){
if(vs[i]==a){
vs[i]=b;
break;
}
}
sort(vs,vs+vp);
}
int block::getans(int m){
int ans=vp-(upper_bound(vs,vs+vp,m)-vs);
for(int i=ss.size()-1;i>=0;i--)ans+=bs[ss[i]].getans(m);
return ans;
}
int dfs(int m,int w){
if(isr[w])return bs[b[w]].getans(m);
int ans=0;
if(v[w]>m)ans++;
for(int i=tr[w].size()-1;i>=0;i--)ans+=dfs(m,tr[w][i]);
return ans;
}
void build(int w,int pa){
if(pa==-1)bs[1].insert(w);
else bs[b[pa]].insert(w);
for(int i=tr0[w].size()-1;i>=0;i--){
int u=tr0[w][i];
if(u!=pa)tr[w].push_back(u);
else continue;
build(u,w);
}
}
int n,m,op,p1,p2,la=0;
int main(){
for(int i=0;i<10005;i++)bs[i].id=i;
scanf("%d",&n);
for(int i=1;i<n;i++){
scanf("%d%d",&p1,&p2);
tr0[p1].push_back(p2);
tr0[p2].push_back(p1);
}
for(int i=1;i<=n;i++){
scanf("%d",&p1);
v[i]=p1;
}
build(1,-1);
tp=n+1;
scanf("%d",&m);
for(int i=0;i<m;i++){
scanf("%d%d%d",&op,&p1,&p2);
p1^=la;p2^=la;
if(op==0){
printf("%d\n",la=dfs(p2,p1));
}else if(op==1){
bs[b[p1]].change(v[p1],p2);
v[p1]=p2;
}else{
tr[p1].push_back(tp);
v[tp]=p2;
bs[b[p1]].insert(tp);
tp++;
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: