其他分享
首页 > 其他分享> > DTOJ #3194. 去月球

DTOJ #3194. 去月球

作者:互联网

【题目描述】

$Scape$ 和 $Mythological$ 交流了玩几何冲刺的经验之后,$Mythological$ 非常高兴,又推荐给 $Scape$ 一款游戏 $To the moon$。

游戏中一位老人 $John$ 的记忆被药物尘封,进行了解除尘封的仪式之后,$Scape$ 走入了他的记忆。

$John$ 的记忆中有一个唤做 $River$ 女孩的身影,有着数不尽的纸兔子,有一个沙包,一只鸭嘴兽玩偶,一座灯塔。$Scape$ 被深深的打动了。

”我的鸭嘴兽和沙包又在哪里呢?” $Scape$ 这样想到,不禁幻想出 $Mythological$ 决定给他送 $n$ 份礼物,其中第 $i$ 份的种类是 $a_i$。这些礼物按顺序排成一行。

她挑选礼物的方式很特别,她每次会选择两份种类相同的礼物,并且这对礼物满足它们之间没有尚未拿走的礼物,并将这对礼物拿走。

现在Scape给出了若干次询问,每次询问如果他送给她的是区间 $[L_i,R_i]$ 之间的礼物,那么她最多能拿走多少份礼物,询问强制在线。

【输入格式】

第 $1$ 行,三个整数 $n,m,q$ 分别是这组测试数据的大小,$a_i$ 的最大可能值,询问个数。

第 $2$ 行, $n$ 个整数,第 $i$ 个整数表示 $a_i$。

接下来 $q$ 行,每行两个整数 $L_i,R_i$,设 $las$ 为上一个询问的答案(初始为 $0$), 则询问的区间为 $[L_i ^ \land las,R_i^ \land las]$(保证合法)。

【输出格式】

共 $q$ 行,表示每个询问的答案。

【样例】

样例输入 
样例输入1
9 10 3
1 1 3 2 1 1 2 3 1
2 9
1 2
2 5
样例输入2
10 10 3
1 2 3 4 5 6 7 8 9 10
1 9
2 3
4 5 

样例输出 
样例输出1
8
2
0
样例输出2
0
0
0

【数据范围与提示】

对于 $20\%$ 的数据,$1\leq n \leq 10^3,1\leq q\leq 10^3$。

对于 $80\%$ 的数据,$1\leq n \leq 10^5,1\leq q\leq 10^5$。

对于 $100\%$ 的数据,$1\leq n \leq 10^5,1\leq m \leq 10^5,1\leq q\leq 2\times 10^6$。

【题解】

首先有一个性质,从左往右能删掉的区间就直接删。不难证明这一定是最优的。

于是就可以对于每个询问从左往右扫一遍,用个栈维护即可。效率 $O(n^2)$。

考虑优化。我们发现,对于一段区间的起点,这个起点一定属于某一个可删除块,而这个起点向后的一部分和向前的一部分应该是相同的。这样向后的一段弹栈的过程就可以理解为在前面一段的压栈过程。

所以一个区间的可删除的点个数就相当于压栈的次数的两倍。压栈次数不好算,我们考虑不删除的部分。我们把栈用一棵 $Trie$ 树维护,用 $map$ 维护每个节点的儿子。

从根节点出发,如果新加入的节点与当前节点颜色相同,执行弹栈操作,跳回父亲节点。如果颜色不同,就沿着该颜色边往下跳。这样每一段可删除的都已经被压缩到一个点里了。

在这棵 $Trie$ 上,每次询问的 $l-1$ 和 $r$ 对应的节点间的距离就是无法删除的部分。往上跳的部分就是对称的部分,而往下跳的部分就刚好是后面多的部分。

由于只求两点间距离,用 $RMQ$ 维护即可。

【代码】

#include<bits/stdc++.h>
namespace IO
{
    char C[1 << 25], D[1 << 25], *S = C;
    int T = 0;
    inline void init (void) { fread (C, 1, 1 << 25, stdin); }
    inline int read (void)
    {
        int x = 0; char c;
        do c = *S++; while ( c < '0' or c > '9' );
        do x = ( x << 1 ) + ( x << 3 ) + c - '0', c = *S++; while ( c >= '0' and c <= '9' );
        return x;
    }
    inline void write (int x)
    {
        if ( !x ) { D[T++] = '0'; D[T++] = '\n'; return; }
        char st[30]; int tp = 0;
        while ( x ) st[++tp] = x % 10 + 48, x /= 10;
        while ( tp ) D[T++] = st[tp--];
        D[T++] = '\n';
    }
    inline void flush (void) { fwrite (D, 1, T, stdout); }
}
const int maxn=200000+10;
int st[maxn][19],fst[maxn],fa[maxn],tot,dep[maxn],Log[maxn],a[maxn],n,m,q,A[maxn];
std::unordered_map<int,int> ch[maxn];
using namespace IO;
std::vector<int> E[maxn];
inline void dfs ( int u )
{
    st[fst[u]=++tot][0]=dep[u];
    for ( int v:E[u] ) dfs(v),st[++tot][0]=dep[u];
}
inline int lca ( int u,int v )
{
    int ql=fst[u],qr=fst[v];
    if ( ql>qr ) std::swap(ql,qr);
    int k=Log[qr-ql+1];
    return std::min(st[ql][k],st[qr-(1<<k)+1][k]);
}
signed main()
{
    init();n=read();m=read();q=read();
    int u=0;
    for ( int i=1;i<=n;i++ )
    {
        a[i]=read()+1;
        if ( a[i]==a[u] ) u=fa[u];
        else
        {
            if ( !ch[u].count(a[i]) ) ch[u][a[i]]=i,E[u].push_back(i),fa[i]=u,dep[i]=dep[u]+1;
            u=ch[u][a[i]];
        }
        A[i]=u;
    }
    dfs(0);
    for ( int i=2;i<=tot;i++ ) Log[i]=Log[i>>1]+1;
    for ( int j=1;j<=Log[tot];j++ ) for ( int i=1;i+(1<<j)-1<=tot;i++ ) st[i][j]=std::min(st[i][j-1],st[i+(1<<(j-1))][j-1]);
    for ( int ans=0,l,r;q--; ) l=read()^ans,r=read()^ans,write(ans=r-l+1-dep[A[l-1]]-dep[A[r]]+2*lca(A[l-1],A[r]));
    flush();
    return 0;
}

 

标签:10,int,样例,leq,3194,Scape,月球,DTOJ,礼物
来源: https://www.cnblogs.com/RenSheYu/p/11329969.html