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;
}

猜你喜欢

转载自blog.csdn.net/zstu_zy/article/details/81675942
LCT