1. 程式人生 > >bzoj 3720: Gty的妹子樹

bzoj 3720: Gty的妹子樹

freopen vector print script 否則 ble 意義 http flag

Description

我曾在弦歌之中聽過你,

檀板聲碎,半出折子戲。

舞榭歌臺被風吹去,

歲月深處尚有余音一縷……


Gty神(xian)犇(chong)從來不缺妹子……

他來到了一棵妹子樹下,發現每個妹子有一個美麗度……

由於Gty很哲♂學,他只對美麗度大於某個值的妹子感興趣。

他想知道某個子樹中美麗度大於k的妹子個數。

某個妹子的美麗度可能發生變化……

樹上可能會出現一只新的妹子……


維護一棵初始有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,輸出一行,包括一個整數,意義見題目描述。

Sample Input

2
1 2
10 20
1
0 1 5

Sample Output

2

HINT

Source

By Autumn

傳說中的樹分塊。。。

將樹分塊,如果父親節點所在的塊已經滿了,就新建一個塊,否則加入父親節點所在的塊;插入節點類似

同時在塊中維護一個有序表,如果遇見整塊就可以直接查詢;

至於查詢的話,直接dfs,如果碰到了與根節點同一個塊的點就暴力統計(因為該塊不一定全在根節點子樹內),否則就直接統計整個塊(易知該塊子樹包含在詢問子樹裏面)

細節有點多。。。

// MADE BY QT666
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<cstring>
#include<vector>
using namespace std;
typedef long long ll;
const int N=100050;
int gi()
{
  int x=0,flag=1;
  char ch=getchar();
  while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘) flag=-1;ch=getchar();}
  while(ch>=‘0‘&&ch<=‘9‘) x=x*10+ch-‘0‘,ch=getchar();
  return x*flag;
}
struct Block{
  int a[210],size;
  void insert(int x){
    size++;int i;
    for(i=size;i>1&&a[i-1]>x;i--) a[i]=a[i-1];
    a[i]=x;
  }
  void update(int x,int y){
    int pl=lower_bound(a+1,a+1+size,x)-a;
    for(;pl<size&&a[pl+1]<y;pl++) a[pl]=a[pl+1];
    for(;pl>1&&a[pl-1]>y;pl--) a[pl]=a[pl-1];
    a[pl]=y;
  }
  int query(int x){
    int pl=upper_bound(a+1,a+1+size,x)-a;
    return size-pl+1;
  }
}block[N];
int cnt,w[N],head[N],to[N],nxt[N],n,m,pos[N],tot,sz,ans,f[N];
vector<int>p[N];
void lnk(int x,int y){
  to[++cnt]=y,nxt[cnt]=head[x],head[x]=cnt;
  to[++cnt]=x,nxt[cnt]=head[y],head[y]=cnt;
}
void build(int x,int fa){
  f[x]=fa;
  if(block[pos[fa]].size==sz){
    tot++;block[tot].insert(w[x]);
    pos[x]=tot;p[pos[fa]].push_back(tot);
  }
  else block[pos[fa]].insert(w[x]),pos[x]=pos[fa];
  for(int i=head[x];i;i=nxt[i]){
    int y=to[i];
    if(y!=fa) build(y,x);
  }
}
void dfs_block(int x,int val){
  ans+=block[x].query(val);
  for(int i=0;i<p[x].size();i++) dfs_block(p[x][i],val);
}
void dfs(int x,int val){
  if(w[x]>val) ans++;
  for(int i=head[x];i;i=nxt[i]){
    int y=to[i];
    if(y!=f[x]){
      if(pos[y]==pos[x]) dfs(y,val);
      else dfs_block(pos[y],val);
    }
  }
}
int main(){
  freopen("1.in","r",stdin);
  freopen("1.out","w",stdout);
  n=gi();
  for(int i=1;i<n;i++){
    int x=gi(),y=gi();lnk(x,y);
  }
  for(int i=1;i<=n;i++) w[i]=gi();
  sz=sqrt(n)+1;build(1,0);
  m=gi();ans=0;
  for(int i=1;i<=m;i++){
    int flag=gi(),u=gi(),v=gi();
    u^=ans,v^=ans;
    if(flag==0){
      ans=0;dfs(u,v);
      printf("%d\n",ans);
    }
    if(flag==1){
      block[pos[u]].update(w[u],v);
      w[u]=v;
    }
    if(flag==2){
      n++;w[n]=v;f[n]=u;lnk(u,n);
      if(block[pos[u]].size==sz){
	tot++;block[tot].insert(w[n]);
	pos[n]=tot;p[pos[u]].push_back(tot);
      }
      else block[pos[u]].insert(w[n]),pos[n]=pos[u];
    }
  }
  return 0;
}

bzoj 3720: Gty的妹子樹