1. 程式人生 > >hdu 6394 分塊大法好 lct

hdu 6394 分塊大法好 lct

Tree
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 446 Accepted Submission(s): 158

Problem Description
Alice and Bob are playing with a magic tree This magic tree has n nodes,with n−1 magic paths connecting them into a connected block. Node 1 is at the top of the magic tree (layer 0). Node i is at the kth layer, where k is the distance from the node i to the node 1. Alice and Bob give a mana value on each node. If a magic stone falls on node i, it will be sent up to the k layer and appear on the kth ancestor node of the i layer(k is the mana value of node i). This node will continue to send up it, and so on. If the layer of node i is less than k, this stone will be sent out of the magic tree. Alice is curious, she will modify the magic value of a node, and ask Bob: If you drop a magic stone on the node x, how many times does it take to transfer it out of the magic tree?

Input
Input contains multiple tests
The first line contains one integer T(T≤4), indicating the number of test cases.
The following lines describe all the test cases
For each test case: The first line contains an integer n(n≤100000), indicating the size of the magic tree.
The second line has n−1 numbers, and the ith number represents the father of the node i+1.
The third row has n numbers, and the ith number represents the initial mana ai(ai≤n) value of each node.
In the fourth line, a number m(m≤100000) represents the number of operations.
The next m lines, one operation per line.
First a number op(1≤op≤2) represents the type of operation.
If op==1, a number x will be read immediately, indicating that a magic stone is thrown to the node x.
If op==2, it will immediately read in two numbers x and new_a, indicating that the magic value of node x is modified to new_a(new_a≤n).

Output
For each query with op==1, output the answer

Sample Input
1
4
1 2 3
1 1 1 1
3
1 4
2 3 2
1 4

Sample Output
4
3

Hint

For the first query: 4->3->2->1->out
For the second query:4->3->1->out

題意:給出一棵樹,然後每個節點有一個權值,代表這個點可以往上面跳多遠,問最少需要多少次可以跳出這顆樹,
做法:分塊,對於每一塊這樣維護,每個點維護兩個值a[i],b[i],a[i]代表這個點需要跳多少次可以跳出這塊,即跳到前面那一塊去,b[i]代表這個點跳出這一塊的時候會跳到那個點去,這樣詢問的時候就可以最多跳sqrt(n)次就以跳出去了,
更新的話,每次把它所在的那一塊全部更新就好了,
思考:分塊不僅可以處理區間查詢問題,它像是一種路徑壓縮,沒隔sqrt(n)做一個標記,然後遍歷就可以在sqrt(n)種完成了,更新的話只需要更新它影響的點,,,emmm,好神奇的樣子,
再說一個分塊的思想:維護可持久化並查集,也可以用分塊來實現,做法就是每隔sqrt(n)就把這個並查集的狀態存下來,然後你想得到的並查集就可以在nsqrt(n),的時間複雜度和空間複雜度下實現了。是不是跟這個很相似,沒有辦法壓縮的路徑,就暴力sqrt(n)維護。

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+337;
int fa[N],a[N],b[N];//a : 需要多少步可以跳到下一個塊,b:跳到下一塊的哪一個點
int lg[N];
int st[N][20];
int B = 333;
int get(int x,int k){
    for(int i = 0;(1<<i) <= k; i ++){
        if((1<<i)&k) x = st[x][i];
    }
    return x;
}

void update(int x){
    int t = x*B;
    if(t == 0){
        a[0] = 0;b[0] = 0;
        t = 1;
    }
    for(int i = t;i < x*B+B;i ++){
        if(fa[i] < x*B) {
            a[i] = 1;
            b[i] = fa[i];
        }
        else{
            a[i] = a[fa[i]]+1;
            b[i] = b[fa[i]];
        }
       // if(i < 10) cout << i << ' '<<a[i] << ' '<<b[i] << ' '<<fa[i] << endl;
    }
}

int query(int x){
    int cnt = 0;
    while(x){
        cnt += a[x];
        x = b[x];
    }
    return cnt;
}

int main(){
    int now = 2;
    lg[1] = 0;
    for(int i = 1;i < N;i ++){
        lg[i] = lg[i-1];
        if(now < i){
            now *= 2;
            lg[i]++;
        }
    }
    int T;
    cin >> T;
    while(T--){
        int n;
        scanf("%d",&n);
        memset(st,0,sizeof(st));
        for(int i = 2;i <= n;i ++){
            scanf("%d",&st[i][0]);
        }
        for(int i = 1;i <= lg[n];i ++){
            for(int j = 1;j <= n;j ++){
                st[j][i] = st[st[j][i-1]][i-1];
            }
        }

        for(int i = 1;i <= n;i ++){
            int now;
            scanf("%d",&now);
            fa[i] = get(i,now);
        }
        for(int i = 0;i <= n/B;i ++){
            update(i);
        }
        int q;
        scanf("%d",&q);
        for(int i = 1;i <= q;i ++){
            int op,x,y;
            scanf("%d",&op);
            if(op == 1){
                scanf("%d",&x);
                printf("%d\n",query(x));
            }
            else{
                scanf("%d %d",&x,&y);
                fa[x] = get(x,y);
                update(x/B);
            }
        }
    }
    return 0;
}

lct:

#include<cstdio>
#include<algorithm>
#include<iostream>
using namespace std;


inline int read(){
    int xx=0,f=1;char ch=getchar();
    for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
    for(;ch>='0'&&ch<='9';ch=getchar())xx=xx*10+ch-'0';
    return xx*f;
}

const int maxn=200010;
int fa[maxn][20];
struct node{
    int fa,ch[2],size;
    bool is_root;
}T[maxn];
int n,m,k[maxn];

void update(int x){
    T[x].size=1;
    if(T[x].ch[0])T[x].size+=T[T[x].ch[0]].size;
    if(T[x].ch[1])T[x].size+=T[T[x].ch[1]].size;
}
int getson(int x){
    return x==T[T[x].fa].ch[1];
}
void rotate(int x){
    if(T[x].is_root)return;
    int k=getson(x),fa=T[x].fa;
    int fafa=T[fa].fa;
    T[fa].ch[k]=T[x].ch[k^1];
    if(T[x].ch[k^1])T[T[x].ch[k^1]].fa=fa;
    T[x].ch[k^1]=fa;
    T[fa].fa=x;
    T[x].fa=fafa;
    if(!T[fa].is_root)T[fafa].ch[fa==T[fafa].ch[1]]=x;
    else T[x].is_root=true,T[fa].is_root=false;
    update(fa);update(x);
}
void Splay(int x){
    for(int fa;!T[x].is_root;rotate(x)){
        if(!T[fa=T[x].fa].is_root){
            rotate((getson(x)==getson(fa))?fa:x);
        }
    }
}
void access(int x){
    int y=0;
    do{
        //cout <<x << ' '<<y << endl;
        Splay(x);
        T[T[x].ch[1]].is_root=true;
        T[T[x].ch[1]=y].is_root=false;
        update(x);
        x=T[y=x].fa;
    }while(x);
}
void link(int u,int v){
    if(v>n)v=0;
    access(u);
    Splay(u);
    T[T[u].ch[0]].is_root=true;
    T[T[u].ch[0]].fa=0;
    T[u].ch[0]=0;
    T[u].fa=v;update(u);
}
int Query(int x){

    access(x);
    //cout<<"!!!" <<x << endl;
    Splay(x);
    return T[T[x].ch[0]].size+1;
}
int get(int x,int y){
    for(int i = 0;(1<<i)<=y;i ++){
        if((1<<i)&y) x = fa[x][i];
    }
    return x;
}
void Work(){
    int opt,x,y;
    while(m--){
        //opt=read();x=read();
        scanf("%d %d",&opt,&x);
        if(opt==1)printf("%d\n",Query(x));
        else if(opt==2){
            //y=read();
            scanf("%d",&y);
            link(x,get(x,y));
        }
    }
}

int main(){
    //n=read();
    int Ts;
    scanf("%d",&Ts);
    while(Ts--){
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            T[i].is_root=T[i].size=1;
            T[i].fa=T[i].ch[0]=T[i].ch[1]=0;
        }
        fa[1][0] =0;
        for(int i = 2;i <= n;i ++){
            int now;
            scanf("%d",&now);
            fa[i][0] = now;
        }
        for(int i = 1;i < 20;i ++){
            for(int j = 1;j <= n;j ++){
                fa[j][i] = fa[fa[j][i-1]][i-1];
            }
        }

        for(int i=1;i<=n;i++){
            //k[i]=read();
            scanf("%d",&k[i]);
            //cout << "!!" << i << ' '<<' '<<k[i] << ' '<< get(i,k[i])<<endl;
            link(i,get(i,k[i]));
        }
        scanf("%d",&m);
        Work();
    }


    return 0;
}