gym 101064 G.The Declaration of Independence (主席树)

题目链接:

题意:

n个操作,有两种操作:

E p  c    在序号为p的队列尾部插入c得到新的队列,序号为i

D p   查询并删除序号为p的队列顶部的元素,得到序号为i的新队列

思路:

需要查询历史版本,我们可以用将这些操作都更新在主席树上,这两个操作可以等价为更新一个点,查询一个点,尾部和顶部的元素我们可以分别用l[i],r[i]来维护第i个队列的顶部元素和尾部元素,查询的时候直接在主席树上找就好了。

实现代码:

#include<iostream>
#include<cstdio>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define mid int m = (l + r) >> 1
const int M = 1e5+10;
int ls[M*40],rs[M*40],sum[M*40],idx,root[M];
void update(int old,int &rt,int p,int c,int l,int r){
    rt = ++idx; ls[rt] = ls[old]; rs[rt] = rs[old];
    sum[rt] = sum[old];
    if(l == r){
        sum[rt] = c;
        return ;
    }
    mid;
    if(p <= m) update(ls[old],ls[rt],p,c,l,m);
    else update(rs[old],rs[rt],p,c,m+1,r);
}

int query(int p,int l,int r,int rt){
    if(l == r) return sum[rt];
    mid;
    if(p <= m) return query(p,l,m,ls[rt]);
    else return query(p,m+1,r,rs[rt]);
}
int n,p,c;
char op[5];
int l[M],r[M];
int main()
{
    idx = 0; l[0] = 1;r [0] = 0;
    scanf("%d",&n);
    for(int i = 1;i <= n;i ++){
        scanf("%s",op);
        if(op[0] == ‘E‘){
            scanf("%d%d",&p,&c);
            l[i] = l[p]; r[i] = r[p];
            update(root[p],root[i],++r[i],c,1,n);
        }
        else {
            scanf("%d",&p);
            l[i] = l[p]; r[i] = r[p]; root[i] = root[p];
            printf("%d\n",query(l[i]++,1,n,root[i]));
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/kls123/p/9600663.html

时间: 2025-01-17 14:04:44

gym 101064 G.The Declaration of Independence (主席树)的相关文章

Gym 101064 D Black Hills golden jewels (二分)

题目链接:http://codeforces.com/gym/101064/problem/D 问你两个数组合相加的第k大数是多少. 先sort数组,二分答案,然后判断其正确性(判断过程是枚举每个数然后二分). 1 //#pragma comment(linker, "/STACK:102400000, 102400000") 2 #include <algorithm> 3 #include <iostream> 4 #include <cstdlib&

【主席树】Gym - 101237A - MEX-Query

主席树里每个值的位置存当前该值出现的最右位置. 如果root[r]的前缀主席树中,某值最右位置大于等于l,说明该值出现在了l,r中. 所以主席树维护区间最小值,如果左半值域的最小值<l,则说明左半值域有值未在l,r出现,则查询左子树:否则查询右子树. #include<cstdio> #include<algorithm> using namespace std; #define N 1000010 struct Node{int v,lc,rc;}T[N*22]; int

(LCA+树上主席树)FZU 2237 - 中位数

题意: 多次查询一个树链上的中位数(其实就是求K大). 分析: 感觉莫队可做,只是不会树上莫队.. 而且这里是边权,处理起来貌似有点小麻烦.. 后来发现其实貌似是一个很老的题,,kuangbin模板书上有类似的题. 树链上的第K大数,这是一道可以用主席树解的题,复杂度才nlogn. 这里也是这样先求从根到每个点的线段树,以为树存在父子关系,所有可以从让下层继承上层的线段树,非常符合主席树的可持久化思想. 然后在查询第K大的时候,去掉重复部分,就可以查了. 太强了,,, 代码: 1 #includ

主席树复习

T1 [CQOI2015]任务查询系统 n个任务,每个有运行的时间段和优先级,询问某一时刻,优先级最小的个任务的优先级之和 初做:  2017.2.4   http://www.cnblogs.com/TheRoadToTheGold/p/6366165.html 好像是做了一晚上来 现在:2017.3.27   14:17——15:56 用了接近2个小时做了一道以前做过的题,还是弱啊~~~~(>_<)~~~~ difference: 主席树维护的东西不同,以前直接存储优先级之和,现在存储的是

Educational Codeforces Round 22 E. Army Creation 主席树 或 分块

E. Army Creation As you might remember from our previous rounds, Vova really likes computer games. Now he is playing a strategy game known as Rage of Empires. In the game Vova can hire n different warriors; ith warrior has the type ai. Vova wants to

hdu_5788_Level Up(树状数组+主席树)

题目链接:hdu_5788_Level Up 题意: 有一棵树,n个节点,每个节点有个能力值A[i],mid[i],mid的值为第i节点的子树的中位数(包括本身),现在让你将其中的一个节点的A值改为1e5,问所有的mid的和最大问多少. 题解: 我们可以知道,如果改变其中一个的A[i],如果A[i]是比他父亲节点的mid小,那么他父亲的此时的中位数就会向后移一位 比如 1 2 3 4 5,第3个点是第2个点的父亲,如果改变了第二个点的A值,那么此时变成了1 3 4 5 1e5,第二个点的父亲的m

bzoj2809 [ APIO2012 ] -- 主席树

先求出dfs序,然后枚举管理者. 由于只要求数量最多,所以薪水一定从小到大取,用主席树维护,每次在主席树上二分就可以了. 具体看代码. 代码: 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<vector> 6 using namespace std; 7 #define N 100010 8 #define

数据结构(主席树):HZOI 2016 采花

[题目描述] 给定一个长度为n,包含c种颜色的序列,有m个询问,每次给出两个数l,r,表示询问区间[l,r]中有多少种颜色的出现次数不少于2次. 本题强制在线,对输入的l,r进行了加密,解密方法为: l = l' xor lastans r = r' xor lastans 其中l', r'为输入的l和r,xor表示异或,lastans为上一次询问的答案且初始值为0. [输入格式] 第一行三个正整数n,c,m,意义与题目描述中的相同. 第二行n个位于[1,c]内的正整数,表示序列上每个位置的颜色

hdu 6162 Ch’s gift(树链剖分+主席树)

题目链接:hdu 6162 Ch's gift 题意: 给你一棵树,树上每个点有一个权值,现在有m个询问,每次询问给你一个s,t,L,R,问你从s到t的路径上,权值在[L,R]内的总和为多少. 题解: 我感觉我写复杂了,用树链剖分来维护路径,然后用主席树来建立权值线段树乱搞. 1 #include<bits/stdc++.h> 2 #define mst(a,b) memset(a,b,sizeof(a)) 3 #define F(i,a,b) for(int i=(a);i<=(b);