zoukankan      html  css  js  c++  java
  • BZOJ2588 主席树 + 树上差分

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

    题意:强制在线的询问树链权值第K小(无修)

    这种类似于第K小的题,一般容易想到主席树,但是树链并不能不是一个按顺序的序列,使用树链剖分也不太容易维护几条链之间的第K小关系。

    但是可以从主席树的前缀和思想入手,一般情况的主席树,查询的时候是query(R) - query(L - 1)来询问区间内的数值数量,在这一题里面,可以考虑到树上差分,从树根开始,以每一个点的父亲为前缀建立主席树。

    然后查询的时候转变为query(u) + query(v) - query(lca(u,v,)) - query(fa(lca(u,v))) 就可以了。

    #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;
    #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;
    int read(){int x = 0,f = 1;char c = getchar();while (c<'0' || c>'9'){if (c == '-') f = -1;c = getchar();}
    while (c >= '0'&&c <= '9'){x = x * 10 + c - '0';c = getchar();}return x*f;}
    const double eps = 1e-9;
    const int maxn = 1e5 + 10;
    const int INF = 0x3f3f3f3f;
    const int mod = 1e9 + 7; 
    int N,M,K;
    int val[maxn],Hash[maxn],tot,cnt,T[maxn];
    struct Edge{
        int to,next;
    }edge[maxn * 2];
    int head[maxn],TOT;
    void init(){
        for(int i = 0 ; i <= N ; i ++) head[i] = -1;
        TOT = tot = 0;
    }
    void add(int u,int v){
        edge[TOT].to = v;
        edge[TOT].next = head[u];
        head[u] = TOT++;
    }
    struct Tree{
        int lt,rt,sum;
    }tree[maxn * 60];
    void newnode(int &t){
        t = ++tot;
        tree[t].sum = 0;
    }
    void Build(int &t,int l,int r){
        newnode(t);
        if(l == r) return;
        int m = l + r >> 1;
        Build(tree[t].lt,l,m); Build(tree[t].rt,m + 1,r);
    }
    void update(int &t,int pre,int l,int r,int p){
        newnode(t);
        tree[t] = tree[pre]; tree[t].sum++;
        if(l == r) return;
        int m = l + r >> 1;
        if(p <= m) update(tree[t].lt,tree[pre].lt,l,m,p);
        else update(tree[t].rt,tree[pre].rt,m + 1,r,p);
    }
    const int SP = 20;
    int fa[maxn][SP],dep[maxn];
    void dfs(int u,int la){
        int p = lower_bound(Hash + 1,Hash + 1 + cnt,val[u]) - Hash;
        update(T[u],T[la],1,cnt,p);
        fa[u][0] = la; dep[u] = dep[la] + 1;
        for(int i = 1; i < SP; i ++) fa[u][i] = fa[fa[u][i - 1]][i - 1];
        for(int i = head[u]; ~i ; i = edge[i].next){
            int v = edge[i].to;
            if(v == la) continue;
            dfs(v,u);
        }
    }
    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; i ++) if(t & (1 << i)) u = fa[u][i];
        for(int i = SP - 1; i >= 0 ; i --){
            int uu = fa[u][i],vv = fa[v][i];
            if(uu != vv){
                u = uu; v = vv;
            }
        }
        return u == v?u:fa[u][0];
    }
    int query(int u,int v,int f,int ff,int l,int r,int k){
        if(l >= r) return l;
        int num = tree[tree[u].lt].sum + tree[tree[v].lt].sum - tree[tree[f].lt].sum - tree[tree[ff].lt].sum;
        int m = l + r >> 1;
        if(k <= num) return query(tree[u].lt,tree[v].lt,tree[f].lt,tree[ff].lt,l,m,k);
        else return query(tree[u].rt,tree[v].rt,tree[f].rt,tree[ff].rt,m + 1,r,k - num);
    }
    int main(){
        Sca2(N,M); init();
        for(int i = 1; i <= N ; i ++) val[i] = Hash[i] = read();
        for(int i = 1; i <= N - 1; i ++){
            int u = read(),v = read();
            add(u,v); add(v,u);
        }
        sort(Hash + 1,Hash + 1 + N);
        cnt = unique(Hash + 1,Hash + 1 + N) - Hash - 1;
        Build(T[0],1,cnt);
        int root = 1; dfs(root,0);
        int ans = 0;
        for(int i = 1; i <= M; i ++){
            int u = read() ^ ans,v = read(),k = read();
            int l = lca(u,v);
            //cout << u << " " << v << " " << l << " " << fa[l][0] << endl;
            ans = Hash[query(T[u],T[v],T[l],T[fa[l][0]],1,cnt,k)];
            Pri(ans);
        }
        return 0;
    }
  • 相关阅读:
    非阻塞式NIO 小案例(模拟聊天室)
    网络通信小案例,服务端接收成功要给客户端一个反馈(阻塞式)
    阻塞式网络通信小案例:
    NIO的非阻塞式网络通信
    字符编码
    使用分散(Scatter)与聚集(Gather)来实现文件的复制
    使用通道之间的数据传输(效果,也是实现文件的复制)
    创建直接缓存区完成文件的复制
    C++预处理详解
    C++的学习资源
  • 原文地址:https://www.cnblogs.com/Hugh-Locke/p/10387514.html
Copyright © 2011-2022 走看看