P4211 [LNOI2014]LCA

P4211 [LNOI2014]LCA

链接

分析:

  首先一种比较有趣的转化是,将所有点到1的路径上都+1,然后z到1的路径上的和,就是所有答案的deep的和。

  对于多次询问,要么考虑有把询问离线,省去每次询问的复杂度,多个一起处理,要么做到优化掉查询。

  这里发现求deep和的过程不能在省了,于是可以差分询问,枚举右端点,然后查询所有1到这个点的和。

  而第一步的操作可以树链剖分完成。(并且查询的是一个区间,这也保证了这样做可行)

  复杂度$O(nlog^2n)$

代码:

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
#include<cctype>
#include<set>
#include<queue>
#include<vector>
#include<map>
#define pa pair<int,int>
using namespace std;
typedef long long LL;

inline int read() {
    int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
    for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
}

const int N = 100005, mod = 201314;
struct Edge{ int to, nxt; } e[N << 1];
int head[N], sum[N << 2], tag[N << 2], fa[N], siz[N], son[N], bel[N], xl[N], ans[N];
int En, Index, n;
vector< pa > Que[N];

inline void add_edge(int u,int v) {
    ++En; e[En].to = v, e[En].nxt = head[u]; head[u] = En;
}
inline void pushdown(int rt,int len) {
    sum[rt << 1] += (len - (len / 2)) * tag[rt];
    sum[rt << 1 | 1] += (len / 2) * tag[rt];
    tag[rt << 1] += tag[rt];
    tag[rt << 1 | 1] += tag[rt];
    tag[rt] = 0;
}
void update(int l,int r,int rt,int L,int R) {
    if (L <= l && r <= R) {
        tag[rt] ++; (sum[rt] += r - l + 1) %= mod; return ;
    }
    if (tag[rt]) pushdown(rt, r - l + 1);
    int mid = (l + r) >> 1;
    if (L <= mid) update(l, mid, rt << 1, L, R);
    if (R > mid) update(mid + 1, r, rt << 1 | 1, L, R);
    sum[rt] = (sum[rt << 1] + sum[rt << 1 | 1]) % mod;
}
int query(int l,int r,int rt,int L,int R) {
    if (L <= l && r <= R) return sum[rt];
    if (tag[rt]) pushdown(rt, r - l + 1);
    int mid = (l + r) >> 1, res = 0;
    if (L <= mid) res = (res + query(l, mid, rt << 1, L, R)) % mod;
    if (R > mid) res = (res + query(mid + 1, r, rt << 1 | 1, L, R)) % mod;
    return res;
}
void dfs1(int u) {
    siz[u] = 1;
    for (int i = head[u]; i; i = e[i].nxt) {
        int v = e[i].to;
        dfs1(v);
        siz[u] += siz[v];
        if (!son[u] || siz[son[u]] < siz[v]) son[u] = v;
    }
}
void dfs2(int u,int top) {
    bel[u] = top;
    xl[u] = ++Index;
    if (!son[u]) return ;
    dfs2(son[u], top);
    for (int i = head[u]; i; i = e[i].nxt) 
        if (e[i].to != son[u]) dfs2(e[i].to, e[i].to);
}
void add(int x) {
    while (x) {
        update(1, n, 1, xl[bel[x]], xl[x]);
        x = fa[bel[x]];
    }
}
int query(int x) {
    int ans = 0;
    while (x) {
        ans = (ans + query(1, n, 1, xl[bel[x]], xl[x])) % mod;
        x = fa[bel[x]];
    }
    return ans;
}
int main() {
    n = read();int m = read();
    for (int i = 2; i <= n; ++i) {
        fa[i] = read() + 1;
        add_edge(fa[i], i);
    }
    dfs1(1);
    dfs2(1, 1);
    for (int i = 1; i <= m; ++i) {
        int l = read() + 1, r = read() + 1, z = read() + 1;
        Que[r].push_back(pa(z, i));
        Que[l - 1].push_back(pa(z, -i));
    }
    for (int i = 1; i <= n; ++i) {
        add(i);
        for (int sz = Que[i].size(), j = 0; j < sz; ++j) {
            if (Que[i][j].second < 0) ans[-Que[i][j].second] -= query(Que[i][j].first);
            else ans[Que[i][j].second] += query(Que[i][j].first);
        }
    }
    for (int i = 1; i <= m; ++i) printf("%d\n", (ans[i] + mod) % mod);
    return 0;
}

 

转载于:https://www.cnblogs.com/mjtcn/p/10347674.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
疫情居家办公系统管理系统按照操作主体分为管理员和用户。管理员的功能包括办公设备管理、部门信息管理、字典管理、公告信息管理、请假信息管理、签到信息管理、留言管理、外出报备管理、薪资管理、用户管理、公司资料管理、管理员管理。用户的功能等。该系统采用了MySQL数据库,Java语言,Spring Boot框架等技术进行编程实现。 疫情居家办公系统管理系统可以提高疫情居家办公系统信息管理问题的解决效率,优化疫情居家办公系统信息处理流程,保证疫情居家办公系统信息数据的安全,它是一个非常可靠,非常安全的应用程序。 管理员权限操作的功能包括管理公告,管理疫情居家办公系统信息,包括外出报备管理,培训管理,签到管理,薪资管理等,可以管理公告。 外出报备管理界面,管理员在外出报备管理界面中可以对界面中显示,可以对外出报备信息的外出报备状态进行查看,可以添加新的外出报备信息等。签到管理界面,管理员在签到管理界面中查看签到种类信息,签到描述信息,新增签到信息等。公告管理界面,管理员在公告管理界面中新增公告,可以删除公告。公告类型管理界面,管理员在公告类型管理界面查看公告的工作状态,可以对公告的数据进行导出,可以添加新公告的信息,可以编辑公告信息,删除公告信息
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值