• bzoj2819 DFS序 + LCA + 线段树


    https://www.lydsy.com/JudgeOnline/problem.php?id=2819

    题意:树上单点修改及区间异或和查询。

    思维难度不高,但是题比较硬核。

    整体思路是维护每一个结点到根节点的距离。查询u,v树链上的异或和就是query(v) ^ query(u) ^ a[lca(u,v)],所以就要想办法维护树上的结点到根节点的异或和。

    网上的题解大多是选择直接维护答案,修改的时候修改整颗子树的答案,用线段树或者树状数组区间异或一下l到r内的答案就可以。

    我一开始没有想到直接上lca直接维护根节点的距离,所以在dfs序上见了一颗线段树,查询的时候query 1到u第一次出现地方的异或和,区间的时候常规单点修改也可过。

    #include <map>
    #include <set>
    #include <ctime>
    #include <cmath>
    #include <queue>
    #include <stack>
    #include <vector>
    #include <string>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <sstream>
    #include <iostream>
    #include <algorithm>
    #include <functional>
    using namespace std;
    inline int read(){int now=0;register char c=getchar();for(;!isdigit(c);c=getchar());
    for(;isdigit(c);now=now*10+c-'0',c=getchar());return now;}
    #define For(i, x, y) for(int i=x;i<=y;i++)  
    #define _For(i, x, y) for(int i=x;i>=y;i--)
    #define Mem(f, x) memset(f,x,sizeof(f))  
    #define Sca(x) scanf("%d", &x)
    #define Sca2(x,y) scanf("%d%d",&x,&y)
    #define Sca3(x,y,z) scanf("%d%d%d",&x,&y,&z)
    #define Scl(x) scanf("%lld",&x);  
    #define Pri(x) printf("%d
    ", x)
    #define Prl(x) printf("%lld
    ",x);  
    #define CLR(u) for(int i=0;i<=N;i++)u[i].clear();
    #define LL long long
    #define ULL unsigned long long  
    #define mp make_pair
    #define PII pair<int,int>
    #define PIL pair<int,long long>
    #define PLL pair<long long,long long>
    #define pb push_back
    #define fi first
    #define se second 
    typedef vector<int> VI;
    const double eps = 1e-9;
    const int maxn = 5e5 + 10;
    const int INF = 0x3f3f3f3f;
    const int mod = 1e9 + 7; 
    int N,M,K;
    LL a[maxn];
    struct Edge{
        int next,to;
    }edge[maxn * 2];
    int head[maxn],tot;
    void init(){
        for(int i = 1; i <= N ; i ++) head[i] = -1;
        tot = 0;
    }
    void add(int u,int v){
        edge[tot].to = v;
        edge[tot].next = head[u];
        head[u] = tot++;
    }
    const int SP = 20;
    int pa[maxn][SP],dep[maxn];
    //求dfs序 
    int num;
    int dfs_index[maxn * 2];
    PII pos[maxn];
    void dfs(int t,int la){
        pa[t][0] = la;
        dep[t] = dep[la] + 1;
        for(int i = 1; i <= SP - 1; i ++) pa[t][i] = pa[pa[t][i - 1]][i - 1];
        pos[t].fi = ++num;
        dfs_index[num] = t;
        for(int i = head[t]; ~i ; i = edge[i].next){
            int v = edge[i].to;
            if(v == la) continue;
            dfs(v,t);
        }
        pos[t].se = ++num;
        dfs_index[num] = t;
    }
    int lca(int u,int v){
        if(dep[u] < dep[v]) swap(u,v);
        int t = dep[u] - dep[v];
        for(int i = 0 ; i <= SP - 1; i ++){
            if(t & (1 << i)) u = pa[u][i];
        }
        for(int i = SP - 1; i >= 0 ; i --){
            int uu = pa[u][i],vv = pa[v][i];
            if(uu != vv){
                u = uu;
                v = vv;
            }
        }
        return u == v? u :pa[u][0];
    }
    //线段树 
    struct Tree{
        LL sum;
    }tree[maxn << 3];
    void Pushup(int t){
        tree[t].sum = tree[t << 1].sum ^ tree[t << 1 | 1].sum; 
    }
    void Build(int t,int l,int r){
        if(l == r){
            tree[t].sum = a[dfs_index[l]];
            return;
        }
        int m = (l + r) >> 1;
        Build(t << 1,l,m); Build(t << 1 | 1,m + 1,r);
        Pushup(t);
    }
    void update(int t,int p,int x,int L,int R){
        if(L == R){
            tree[t].sum = x;
            return;
        }
        int m = (L + R) >> 1;
        if(p <= m) update(t << 1,p,x,L,m);
        else update(t << 1 | 1,p,x,m + 1,R);
        Pushup(t);
    }
    LL query(int t,int l,int r,int L,int R){
        if(l <= L && R <= r){
            return tree[t].sum;
        }
        int m = (L + R) >> 1;
        if(r <= m) return query(t << 1,l,r,L,m);
        else if(l > m) return query(t << 1 | 1,l,r,m + 1,R);
        else return query(t << 1,l,m,L,m) ^ query(t << 1 | 1,m + 1,r,m + 1,R);
    }
    
    LL query(int x){
        return query(1,1,pos[x].fi,1,2 * N);
    }
    int main(){
        Sca(N); init();
        For(i,1,N) Scl(a[i]);
        For(i,1,N - 1){
            int u,v; Sca2(u,v);
            add(u,v); add(v,u);
        }
        dfs(1,0);
        Build(1,1,2 * N);
        Sca(K);
        while(K--){
            char op[3];
            int u,v;
            scanf("%s%d%d",op,&u,&v);
            if(op[0] == 'Q'){
                if(query(u) ^ query(v) ^ a[lca(u,v)]) puts("Yes");
                else puts("No");
            }else{
                update(1,pos[u].fi,v,1,2 * N);
                update(1,pos[u].se,v,1,2 * N);
                a[u] = v;
            }
        }
        return 0;
    }
  • 相关阅读:
    WPF中C#代码触发鼠标点击事件
    PHP代码实现强制换行
    C#中判断系统的架构(32位,还是64位)
    WPF的System.Windows.Threading.DispatcherTimer的使用(每隔一定的时间重复做某事)
    LINQ to Objects系列(2)两种查询语法介绍
    LINQ to Objects系列(1)相关技术准备
    常用技术社区和网站总结
    .net项目技术选型总结
    java与.net比较学习系列(7) 属性
    java与.net比较学习系列(6) 数组
  • 原文地址:https://www.cnblogs.com/Hugh-Locke/p/10266255.html
Copyright © 2020-2023  润新知