[LOJ3088][GXOI/GZOI2019]旧词——树链剖分+线段树
题目链接:
对于$k=1$的情况,可以参见[LNOI2014]LCA,将询问离线然后从$1$号点开始对这个点到根的路径链修改,每次询问就是对询问点到根路径链查询即可。
可以发现,如果一个点的贡献被记入答案,那么这个点到根的路径上所有点的贡献都会被记入答案。
那么对于$k>1$的情况,只要每次将路径上点$u$的权值都$+1$变成每次将路径上点$u$的权值都$+(dep[u]^k-(dep[u]-1)^k)$即可。
同样用线段树维护树剖序的区间权值和即可。
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<vector>
#include<bitset>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
const int mod=998244353;
int n,m,k;
int ans[50010];
int p[50010];
int son[50010];
int size[50010];
int f[50010];
int tot;
int head[50010];
int to[50010];
int nex[50010];
int dep[50010];
int top[50010];
int s[50010];
int q[50010];
int dfn;
int sum[400010];
int num[400010];
int tag[400010];
struct lty
{
int x,y,id;
}a[50010];
bool cmp(lty a,lty b)
{
return a.x<b.x;
}
int quick(int x,int y)
{
int res=1;
while(y)
{
if(y&1)
{
res=1ll*res*x%mod;
}
x=1ll*x*x%mod;
y>>=1;
}
return res;
}
void add_edge(int x,int y)
{
nex[++tot]=head[x];
head[x]=tot;
to[tot]=y;
}
int add(int x,int y)
{
if(x+y<mod)
{
return x+y;
}
else
{
return x+y-mod;
}
}
void dfs(int x)
{
size[x]=1;
for(int i=head[x];i;i=nex[i])
{
dep[to[i]]=dep[x]+1;
dfs(to[i]);
size[x]+=size[to[i]];
if(size[to[i]]>size[son[x]])
{
son[x]=to[i];
}
}
}
void dfs2(int x,int tp)
{
top[x]=tp;
s[x]=++dfn;
q[dfn]=x;
if(son[x])
{
dfs2(son[x],tp);
}
for(int i=head[x];i;i=nex[i])
{
if(to[i]!=son[x])
{
dfs2(to[i],to[i]);
}
}
}
void pushup(int rt)
{
sum[rt]=add(sum[rt<<1],sum[rt<<1|1]);
num[rt]=add(num[rt<<1],num[rt<<1|1]);
}
void pushdown(int rt)
{
if(tag[rt])
{
tag[rt<<1]=add(tag[rt],tag[rt<<1]);
tag[rt<<1|1]=add(tag[rt],tag[rt<<1|1]);
sum[rt<<1]=add(sum[rt<<1],1ll*tag[rt]*num[rt<<1]%mod);
sum[rt<<1|1]=add(sum[rt<<1|1],1ll*tag[rt]*num[rt<<1|1]%mod);
tag[rt]=0;
}
}
void build(int rt,int l,int r)
{
if(l==r)
{
num[rt]=p[dep[q[l]]];
return ;
}
int mid=(l+r)>>1;
build(rt<<1,l,mid);
build(rt<<1|1,mid+1,r);
pushup(rt);
}
void change(int rt,int l,int r,int L,int R)
{
if(L<=l&&r<=R)
{
tag[rt]=add(tag[rt],1);
sum[rt]=add(sum[rt],num[rt]);
return ;
}
int mid=(l+r)>>1;
pushdown(rt);
if(L<=mid)
{
change(rt<<1,l,mid,L,R);
}
if(R>mid)
{
change(rt<<1|1,mid+1,r,L,R);
}
pushup(rt);
}
int query(int rt,int l,int r,int L,int R)
{
if(L<=l&&r<=R)
{
return sum[rt];
}
int mid=(l+r)>>1;
int res=0;
pushdown(rt);
if(L<=mid)
{
res=add(res,query(rt<<1,l,mid,L,R));
}
if(R>mid)
{
res=add(res,query(rt<<1|1,mid+1,r,L,R));
}
return res;
}
void modify(int x)
{
while(top[x]!=1)
{
change(1,1,n,s[top[x]],s[x]);
x=f[top[x]];
}
change(1,1,n,1,s[x]);
}
int ask(int x)
{
int res=0;
while(top[x]!=1)
{
res=add(res,query(1,1,n,s[top[x]],s[x]));
x=f[top[x]];
}
res=add(res,query(1,1,n,1,s[x]));
return res;
}
int main()
{
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=n;i++)
{
p[i]=(quick(i,k)-quick(i-1,k)+mod)%mod;
}
dep[1]=1;
for(int i=2;i<=n;i++)
{
scanf("%d",&f[i]);
add_edge(f[i],i);
}
dfs(1);
dfs2(1,1);
build(1,1,n);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&a[i].x,&a[i].y);
a[i].id=i;
}
sort(a+1,a+1+m,cmp);
int now=0;
for(int i=1;i<=m;i++)
{
while(now<a[i].x)
{
now++;
modify(now);
}
ans[a[i].id]=ask(a[i].y);
}
for(int i=1;i<=m;i++)
{
printf("%d\n",ans[i]);
}
}
[LOJ3088][GXOI/GZOI2019]旧词——树链剖分+线段树的更多相关文章
- 【BZOJ-2325】道馆之战 树链剖分 + 线段树
2325: [ZJOI2011]道馆之战 Time Limit: 40 Sec Memory Limit: 256 MBSubmit: 1153 Solved: 421[Submit][Statu ...
- 【BZOJ2243】[SDOI2011]染色 树链剖分+线段树
[BZOJ2243][SDOI2011]染色 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的 ...
- BZOJ2243 (树链剖分+线段树)
Problem 染色(BZOJ2243) 题目大意 给定一颗树,每个节点上有一种颜色. 要求支持两种操作: 操作1:将a->b上所有点染成一种颜色. 操作2:询问a->b上的颜色段数量. ...
- POJ3237 (树链剖分+线段树)
Problem Tree (POJ3237) 题目大意 给定一颗树,有边权. 要求支持三种操作: 操作一:更改某条边的权值. 操作二:将某条路径上的边权取反. 操作三:询问某条路径上的最大权值. 解题 ...
- bzoj4034 (树链剖分+线段树)
Problem T2 (bzoj4034 HAOI2015) 题目大意 给定一颗树,1为根节点,要求支持三种操作. 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子 ...
- HDU4897 (树链剖分+线段树)
Problem Little Devil I (HDU4897) 题目大意 给定一棵树,每条边的颜色为黑或白,起始时均为白. 支持3种操作: 操作1:将a->b的路径中的所有边的颜色翻转. 操作 ...
- Aizu 2450 Do use segment tree 树链剖分+线段树
Do use segment tree Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.bnuoj.com/v3/problem_show ...
- 【POJ3237】Tree(树链剖分+线段树)
Description You are given a tree with N nodes. The tree’s nodes are numbered 1 through N and its edg ...
- HDU 2460 Network(双连通+树链剖分+线段树)
HDU 2460 Network 题目链接 题意:给定一个无向图,问每次增加一条边,问个图中还剩多少桥 思路:先双连通缩点,然后形成一棵树,每次增加一条边,相当于询问这两点路径上有多少条边,这个用树链 ...
- bzoj2243[SDOI2011]染色 树链剖分+线段树
2243: [SDOI2011]染色 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 9012 Solved: 3375[Submit][Status ...
随机推荐
- DSAPI 图形图像篇(上)
彩色文字对象 基于一些特殊需求,本人开发了彩色文字对象,该功能通过类似html代码的方式指示文本,并输出图像. 我们还是先来看一张图像. 这不是文本,是通过指定文本代码输出的图像.我们来看一下实现代码 ...
- spring的理解
看过<fate系列>的博友知道,这是一个七位英灵的圣杯争夺战争.今天主要来谈谈圣杯的容器概念,以便对spring的理解. 圣杯: 圣杯本身是没有实体的,而是将具有魔术回路的存在(人)作为“ ...
- 学JAVA第十三天,方法、方法重载及构造函数
今天终于不讲狗跳楼的问题了,今天讲了方法,方法重载及构造函数及构造函数重载的课程了. 这里说了有参好无参的,下面讲构造函数重载和方法重载. 其实,这上面写的这些方法,就相当一个模板.想要快速做出产品就 ...
- oracle学习笔记(三) DCL 数据控制语言与 DDL 数据定义语言
DCL 数据控制语言 Data control language 之前说过的授权和收权利语句 grant, revoke DDL 数据定义语言 Data define language create ...
- 如何将workerman部署到windows服务器上面
一直以来对php的即时通讯都很好奇,其实是不知道应该怎么来实现,后来了解到了swoole和workerman这两个神器,他们都可以实现即时通信的功能,其中swoole是C语言编写的php扩展,其配置起 ...
- springboot源码分析-SpringApplication
SpringApplication SpringApplication类提供了一种方便的方法来引导从main()方法启动的Spring应用程序 SpringBoot 包扫描注解源码分析 @Spring ...
- 通过JS动态的修改HTML元素的样式和增添标签元素等
一. 通过JS动态的修改HTML元素的样式 1. 要想在js中动态的修改HTML元素的样式,首先需要写document, document我们称之为文档对象,这个对象中保存了当前网页中所有的 ...
- [C#学习笔记3]关于Main(string[ ] args)中args命令行参数
Main(string[] args)方法是C#程序的入口,程序从这里开始执行,在这里结束.C#代码逻辑要包含在一个类型(Type)中,游离的.全局的变量或函数是不存在的,这里的类型包括类(class ...
- arcgis api 3.x for js 入门开发系列十五台风轨迹
前言 关于本篇功能实现用到的 api 涉及类看不懂的,请参照 esri 官网的 arcgis api 3.x for js:esri 官网 api,里面详细的介绍 arcgis api 3.x 各个类 ...
- android 卡顿 Matrix TraceCanary
转载: 通过观察大盘整体的帧率及掉帧程度,来评估并监控一些重要场景的流畅性.通过一个闭环的流程,利用 Matrix-TraceCanary 模块从客户端对卡顿进行捕捉与分析上报,通过后台聚类问题堆栈及 ...