[bzoj3720]Gty的妹子樹

3720: Gty的妹子樹

Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 963 Solved: 331
[Submit][Status][Discuss]
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

我這道題用的是對進棧順序的dfs 序序列分塊的,。
樹還有很多分塊的方法:

王室聯邦那個題就是相當於對出棧順序的dfs序序列分塊的。
還可以對子樹大小進行限制來分塊。
...

我是對於dfs 序列中的每個塊維護最小的深度了,就記爲mind 了。
這樣每次查詢一個子樹的時候,從根走完這個塊後,看看下一個塊的mind 是否> 根的deep ,如果大於的話,統計一下這個區間內的答案,再到下一個塊。一直走到一個塊的mind<=deep[root] 這個時候再暴力算一下答案。
對於這個題插入節點的問題:每次插入的時候都放到它爸爸後面的第一個,暴力改一下這個塊後面的元素在這個塊內的順序。


寫完之後T 了,然後開始調常數,調的過程中發現塊越大跑的越快,然後就很愉悅的A 了 。
爲什麼塊越大越快呢?
可以這樣想一下:每次的查詢操作是O(nlogn) ,但是修改的複雜度只有O(nlog(n)) 就算是O(n) 的吧。
這樣我們會發現如果塊的大小變大的話, 雖然會加大修改的複雜度,但是查詢時候的在塊中二分的次數會減少很多,所以總體上的複雜度會更優越。
TA 的證明:設塊的大小是x ,那麼複雜度就是x+nlognx 那麼取最小值的時候x=nlogn (均值不等式)。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
#define inf 0x7fffffff
const int N=60010;
struct S{int st,en;}aa[N<<1];
struct B{int v,No,num,dep;}block[400][(400+10)<<1];
int n,m,tot,point[N],next[N<<1],w[N],o,in[N],min_d[N],to[N],ans,siz[N];
inline int IN(){
    int x=0;char ch=getchar();
    while(ch<'0'||ch>'9') ch=getchar();
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x;
}
inline void add(int x,int y){
    next[++tot]=point[x];point[x]=tot;
    aa[tot].st=x;aa[tot].en=y;
    next[++tot]=point[y];point[y]=tot;
    aa[tot].st=y;aa[tot].en=x;
}
int pos[N],dfsn,deep[N],map[N];
inline void dfs(int x,int last){
    int i;
    pos[x]=++dfsn;
    map[dfsn]=x;
    for(i=point[x];i;i=next[i])
      if(aa[i].en!=last){
        deep[aa[i].en]=deep[x]+1;
        dfs(aa[i].en,x);
      }
}
inline bool cmp_v(B x,B y){return x.v>y.v;}
inline bool cmp_No(B x,B y){return x.No<y.No;}
#define mid (l+r)/2
int main(){
    int i,j,x,y,t,l,r;
    n=IN();
    int O=(int)(sqrt(n)*0.4);
    for(i=1;i<n;++i){
        x=IN();y=IN();
        add(x,y);
    }
    for(i=1;i<=n;++i) w[i]=IN();
    dfs(1,0);
    memset(min_d,127,sizeof(min_d));
    for(j=o=1,i=1;i<=n;++i){
        in[map[i]]=o;++siz[o];
        min_d[o]=min(min_d[o],deep[map[i]]);
        block[o][j].No=j;
        block[o][j].v=w[map[i]];
        block[o][j].num=map[i];
        block[o][j].dep=deep[map[i]];
        if((++j)>O) j=1,++o;
    }
    for(i=1;i<=o;++i) sort(block[i]+1,block[i]+siz[i]+1,cmp_v),to[i]=i+1;
    to[o]=inf;
    m=IN();
    while(m--){
        t=IN();x=IN();y=IN();
        x^=ans;y^=ans;
        int now=in[x];
        if(t==0){
            bool flag=true;
            sort(block[now]+1,block[now]+siz[now]+1,cmp_No);
            for(i=1;i<=siz[now];++i)
              if(block[now][i].num==x) break;
            ans=(block[now][i].v>y);
            int limit=block[now][i].dep;
            for(i=i+1;i<=siz[now]&&flag;++i)
              if(block[now][i].dep>limit) ans+=(block[now][i].v>y);
              else flag=false;
            sort(block[now]+1,block[now]+siz[now]+1,cmp_v);
            if(!flag){
                printf("%d\n",ans);
                continue;
            }
            for(i=to[now];i&&i!=inf;i=to[i])
              if(min_d[i]>limit){
                l=1,r=siz[i];
                int maxn=0;
                while(l<=r){
                    if(block[i][mid].v>y) maxn=max(maxn,mid),l=mid+1;
                    else r=mid-1;
                }
                ans+=maxn;
              }
              else break;
            if(i==inf){
                printf("%d\n",ans);
                continue;
            }
            sort(block[i]+1,block[i]+siz[i]+1,cmp_No);
            for(j=1;j<=siz[i]&&block[i][j].dep>limit;++j)
              ans+=(block[i][j].v>y);
            sort(block[i]+1,block[i]+siz[i]+1,cmp_v);
            printf("%d\n",ans);
        }
        if(t==1){
            for(i=1;i<=siz[now];++i)
              if(block[now][i].num==x){
                block[now][i].v=y;
                break;
              }
            sort(block[now]+1,block[now]+siz[now]+1,cmp_v);
        }
        if(t==2){
            if(siz[now]+1==O*2){
                sort(block[now]+1,block[now]+O*2,cmp_No);
                ++o;siz[now]=siz[o]=O;++n;
                to[o]=to[now];to[now]=o;
                for(i=1;i<O<<1;++i)
                  if(block[now][i].num==x) break;
                block[now][O<<1].No=block[now][i].No+1;
                for(i=i+1;i<O<<1;++i) block[now][i].No+=1;
                block[now][O<<1].v=y;
                block[now][O<<1].num=n;
                deep[n]=block[now][O<<1].dep=deep[x]+1;
                sort(block[now]+1,block[now]+O*2+1,cmp_No);
                for(i=O+1;i<=O<<1;++i){
                    block[o][i-O]=block[now][i];
                    in[block[o][i-O].num]=o;
                    block[o][i-O].No=i-O;
                }
                if(!in[n]) in[n]=now;
                for(min_d[now]=inf,i=1;i<=O;++i) min_d[now]=min(min_d[now],block[now][i].dep);
                for(min_d[o]=inf,i=1;i<=O;++i) min_d[o]=min(min_d[o],block[o][i].dep);
                sort(block[now]+1,block[now]+O+1,cmp_v);
                sort(block[o]+1,block[o]+O+1,cmp_v);
            }
            else{
                sort(block[now]+1,block[now]+siz[now]+1,cmp_No);
                in[++n]=now;
                for(i=1;i<=siz[now];++i)
                  if(block[now][i].num==x) break;
                block[now][++siz[now]].No=block[now][i].No+1;
                for(i=i+1;i<siz[now];++i) block[now][i].No+=1;
                block[now][siz[now]].v=y;
                block[now][siz[now]].num=n;
                deep[n]=block[now][siz[now]].dep=deep[x]+1;
                sort(block[now]+1,block[now]+siz[now]+1,cmp_v);
            }
        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章