【GDOI2017模拟2.14】A

本文介绍了一种使用主席树解决区间查询问题的有效方法,并通过一个具体的题目实例详细展示了实现过程。文章首先概述了问题背景及数据约束,接着阐述了解决方案的思路,包括离线方法与在线方法的对比,最终选择了主席树作为主要的数据结构。文中还提供了完整的代码实现,有助于读者理解整个算法的设计和应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description
这里写图片描述
Input

这里写图片描述
Sample Input

5 5 4
3 4 2 3 3
2 4
5 1
1 3
2 1
2 5 2
6 7 0
7 7 0
2 4 2
这里写图片描述
Sample Output

0 0 3
0 3 1
0 0 1
1 2 0

Data Constraint
这里写图片描述
注意:Q<=300000

Hint
这里写图片描述

题解

一开始想的是用一些神奇的离线方法做,想了半天之后发现这题是强制在线的QAQ
然后就看了一发题解,结果题解只有:主席树入门题这几个字(。・・)ノ
想了一会儿之后想到可以用权值线段树对每个节点维护它到根节点路径上点权值的分布情况
于是就发现了用主席树的方法

首先我们用主席树预处理每一个节点到根节点路径的点权值的情况,然后每一次询问一组(x,y),我们就可以随便倍增一下,然后主席树快速算出两点之间的点的分布情况就可以了

贴代码

var
    tree:array[0..6000005,1..3]of longint;
    a,b:array[0..600005,1..2]of longint;
    bz:array[0..300005]of boolean;
    cc,root,fa,deep:array[0..300005]of longint;
    ff:array[0..300005,0..19]of longint;
    i,j,k,l,m,n,x,y,z,p,last,tmp,t,xx,yy,q:longint;
    tt:array[0..3]of longint;
procedure qsort(l,r:longint);
var
    i,j,mid:longint;
begin
    i:=l;
    j:=r;
    mid:=a[(i+j) div 2,1];
    repeat
        while a[i,1]<mid do inc(i);
        while a[j,1]>mid do dec(j);
        if i<=j then
        begin
            a[0]:=a[i];
            a[i]:=a[j];
            a[j]:=a[0];
            inc(i);
            dec(j);
        end;
    until i>j;
    if i<r then qsort(i,r);
    if l<j then qsort(l,j);
end;
procedure star;
begin
    b[a[1,1],1]:=1;
    for i:=2 to n*2-2 do
    if a[i,1]<>a[i-1,1] then
    begin
        b[a[i-1,1],2]:=i-1;
        b[a[i,1],1]:=i;
    end;
    b[a[i,1],2]:=i;
end;
procedure make_ff;
var
    i,j:longint;
begin
    for j:=1 to 18 do
        for i:=1 to n do ff[i,j]:=ff[ff[i,j-1],j-1];
end;
procedure maketree(var num,x:longint;l,r:longint);
var
    mid:longint;
begin
    tree[p]:=tree[x];
    inc(tree[p,3]);
    x:=p;
    inc(p);
    if l=r then exit;
    mid:=(l+r) div 2;
    if num<=mid then maketree(num,tree[x,1],l,mid)
        else maketree(num,tree[x,2],mid+1,r);
end;
procedure find(v1,v2,l,r,x,y,z:longint);
var
    mid:longint;
begin
    if (l=x) and (r=y) then
        tt[z]:=tt[z]+tree[v2,3]-tree[v1,3]
    else
    begin
        mid:=(l+r) div 2;
        if y<=mid then find(tree[v1,1],tree[v2,1],l,mid,x,y,z) else
        if x>mid then find(tree[v1,2],tree[v2,2],mid+1,r,x,y,z) else
        begin
            find(tree[v1,1],tree[v2,1],l,mid,x,mid,z);
            find(tree[v1,2],tree[v2,2],mid+1,r,mid+1,y,z);
        end;
    end;
end;
procedure dfs(x:longint);
var
    i:longint;
begin
    bz[x]:=true;
    for i:=b[x,1] to b[x,2] do
    if (i<>0) and (bz[a[i,2]]=false) then
    begin
        fa[a[i,2]]:=x;
        ff[a[i,2],0]:=x;
        deep[a[i,2]]:=deep[x]+1;
        root[a[i,2]]:=root[x];
        maketree(cc[a[i,2]],root[a[i,2]],1,m);
        dfs(a[i,2]);
    end;
end;
begin
    //assign(input,'jzoj4969.in'); reset(input);
    assign(input,'a.in'); reset(input);
    assign(output,'a.out'); rewrite(output);
    readln(n,m,q);
    for i:=1 to n do read(cc[i]);
    readln;
    for i:=1 to n-1 do
    begin
        readln(a[i,1],a[i,2]);
        a[n+i-1,1]:=a[i,2];
        a[n+i-1,2]:=a[i,1];
    end;
    qsort(1,n*2-2);
    star;
    p:=1;
    maketree(cc[1],root[1],1,m);
    deep[1]:=1;
    dfs(1);
    make_ff;
    for i:=1 to q do
    begin
        readln(x,y,z);
        x:=x xor last;
        y:=y xor last;
        z:=z xor last;
        xx:=x;
        yy:=y;
        if deep[y]>deep[x] then
        begin
            tmp:=x;
            x:=y;
            y:=tmp;
        end;
        k:=deep[x];
        for j:=18 downto 0 do
        if k-1<<j>=deep[y] then
        begin
            k:=k-1<<j;
            x:=ff[x,j];
        end;
        for j:=18 downto 0 do
        if ff[x,j]<>ff[y,j] then
        begin
            x:=ff[x,j];
            y:=ff[y,j];
        end;
        if x<>y then x:=ff[x,0];
        fillchar(tt,sizeof(tt),0);
        if z>1 then
        begin
            find(root[x],root[xx],1,m,1,z-1,1);
            find(root[x],root[yy],1,m,1,z-1,1);
        end;
        find(root[x],root[xx],1,m,z,z,2);
        find(root[x],root[yy],1,m,z,z,2);
        if z<m then
        begin
            find(root[x],root[xx],1,m,z+1,m,3);
            find(root[x],root[yy],1,m,z+1,m,3);
        end;
        if cc[x]<z then inc(tt[1]) else
        if cc[x]=z then inc(tt[2]) else
        inc(tt[3]);
        last:=tt[1] xor tt[2];
        last:=last xor tt[3];
        writeln(tt[1],' ',tt[2],' ',tt[3]);
    end;
    close(input); close(output);
end.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值