CF1254D Tree Queries(树链剖分)
出题人的做法是 \(O(n\sqrt{n\log n})\),结果这场结束后就被狂喷,一群人给出了 \(O(n\sqrt{n})\) 做法,甚至 \(O(n\log n)\) 都出来了……
首先发现,修改一个点时,如果把这个点看成根,其它点权期望的变化只和在根的哪个儿子的子树中有关,\(\frac{n-sz[u]}{n}d\)(选除了这个子树中的点都能经过 \(x\))。
\(O(n\sqrt{n\log n})\) 很显然,对修改的点的度数分类讨论,度数小的就是一堆子树加,度数大的就打个标记,查询的时候把大点的贡献也算上就行了。
\(O(n\sqrt{n})\) 的话,把线段树/树状数组换成分块。度数小的修改复杂度总共是 \(O(\text{块数}+\text{度数})\)(每棵子树的区间不交)。
\(O(n\log n)\) 就不用度数根号分治了。
考虑树剖(似乎很套路?),修改一个点时,只需要对重儿子和外子树区间加。
询问一个点时,发现需要再统计的就是跳重链时,从一条链跳到另外一条链时链头和父亲之间的贡献(只有这时才有轻儿子)。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int maxn=300030,mod=998244353;
#define MP make_pair
#define PB push_back
#define lson o<<1,l,mid
#define rson o<<1|1,mid+1,r
#define FOR(i,a,b) for(int i=(a);i<=(b);i++)
#define ROF(i,a,b) for(int i=(a);i>=(b);i--)
#define MEM(x,v) memset(x,v,sizeof(x))
inline ll read(){
char ch=getchar();ll x=0,f=0;
while(ch<'0' || ch>'9') f|=ch=='-',ch=getchar();
while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
return f?-x:x;
}
int n,q,el,head[maxn],to[maxn],nxt[maxn],b[maxn],dep[maxn],sz[maxn],son[maxn],fa[maxn],top[maxn],lft[maxn],rig[maxn],cnt,tag[maxn];
inline void add(int u,int v){
to[++el]=v;nxt[el]=head[u];head[u]=el;
}
inline int qpow(int a,int b){
int ans=1;
for(;b;b>>=1,a=1ll*a*a%mod) if(b&1) ans=1ll*ans*a%mod;
return ans;
}
inline void update(int p,int v){
for(int i=p;i<=n;i+=i&-i) b[i]=(b[i]+v)%mod;
}
inline void update(int l,int r,int v){
update(l,v);update(r+1,(mod-v)%mod);
}
inline int query(int p){
int s=0;
for(int i=p;i;i-=i&-i) s=(s+b[i])%mod;
return s;
}
void dfs1(int u,int f){
dep[u]=dep[fa[u]=f]+1;
sz[u]=1;
for(int i=head[u];i;i=nxt[i]){
int v=to[i];
if(v==f) continue;
dfs1(v,u);
sz[u]+=sz[v];
if(sz[v]>sz[son[u]]) son[u]=v;
}
}
void dfs2(int u,int topf){
top[u]=topf;
lft[u]=++cnt;
if(son[u]) dfs2(son[u],topf);
for(int i=head[u];i;i=nxt[i]){
int v=to[i];
if(v==fa[u] || v==son[u]) continue;
dfs2(v,v);
}
rig[u]=cnt;
}
void update_tree(int u,int d){
tag[u]=(tag[u]+d)%mod;
if(son[u]) update(lft[son[u]],rig[son[u]],1ll*(n-sz[son[u]])*d%mod);
if(u!=1){
update(1,lft[u]-1,1ll*sz[u]*d%mod);
if(rig[u]!=n) update(rig[u]+1,n,1ll*sz[u]*d%mod);
}
}
int query_tree(int u){
int s=(1ll*n*tag[u]+query(lft[u]))%mod;
while(u){
s=(s+1ll*tag[fa[top[u]]]*(n-sz[top[u]]))%mod;
u=fa[top[u]];
}
return s;
}
int main(){
n=read();q=read();
int inv=qpow(n,mod-2);
FOR(i,1,n-1){
int u=read(),v=read();
add(u,v);add(v,u);
}
dfs1(1,0);dfs2(1,1);
while(q--){
int tp=read(),u=read();
if(tp==1) update_tree(u,1ll*inv*read()%mod);
else printf("%d\n",query_tree(u));
}
}
CF1254D Tree Queries(树链剖分)的更多相关文章
- HDU 4718 The LCIS on the Tree(树链剖分)
Problem Description For a sequence S1, S2, ... , SN, and a pair of integers (i, j), if 1 <= i < ...
- Codeforces Round #329 (Div. 2) D. Happy Tree Party 树链剖分
D. Happy Tree Party Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/593/p ...
- 南昌网络赛J. Distance on the tree 树链剖分
Distance on the tree 题目链接 https://nanti.jisuanke.com/t/38229 Describe DSM(Data Structure Master) onc ...
- 【POJ3237】Tree(树链剖分)
题意:在一棵N个节点,有边权的树上维护以下操作: 1:单边修改,将第X条边的边权修改成Y 2:区间取反,将点X与Y在树上路径中的所有边边权取反 3:区间询问最大值,询问X到Y树上路径中边权最大值 n& ...
- POJ 3237:Tree(树链剖分)
http://poj.org/problem?id=3237 题意:树链剖分.操作有三种:改变一条边的边权,将 a 到 b 的每条边的边权都翻转(即 w[i] = -w[i]),询问 a 到 b 的最 ...
- QTREE3 spoj 2798. Query on a tree again! 树链剖分+线段树
Query on a tree again! 给出一棵树,树节点的颜色初始时为白色,有两种操作: 0.把节点x的颜色置反(黑变白,白变黑). 1.询问节点1到节点x的路径上第一个黑色节点的编号. 分析 ...
- spoj 375 Query on a tree(树链剖分,线段树)
Query on a tree Time Limit: 851MS Memory Limit: 1572864KB 64bit IO Format: %lld & %llu Sub ...
- bzoj 3637: Query on a tree VI 树链剖分 && AC600
3637: Query on a tree VI Time Limit: 8 Sec Memory Limit: 1024 MBSubmit: 206 Solved: 38[Submit][Sta ...
- poj 3237 Tree(树链剖分,线段树)
Tree Time Limit: 5000MS Memory Limit: 131072K Total Submissions: 7268 Accepted: 1969 Description ...
- 【POJ3237】Tree(树链剖分+线段树)
Description You are given a tree with N nodes. The tree’s nodes are numbered 1 through N and its edg ...
随机推荐
- Elasticsearch实现复合查询,高亮结果等技巧
一.Es的配置 实现es的全文检索功能的第一步,首先从与es进行连接开始,这里我使用的是es的5.x java api语法. public TransportClient esClient() thr ...
- Dotnetcore或owin程序启用SSL的方法
https端口需要绑定SSL证书 操作方法与步骤如下: 在IIS中创建证书 查看证书的指纹 使用命令行绑定端口与证书 上述第三步也可以更换为创建一个新的空网站,绑定https端口为相同端口并绑定证书, ...
- SQL Server如何通过Page_ID找到对应的表
其实本篇文章算是翻译Finding a table name from a page ID这篇文章,只是不想直接翻译.用自己的理解叙说出来.算是对上一篇博客"SQL Server如何找出一个 ...
- Tornado—添加请求头允许跨域请求访问
跨域请求访问 如果是前后端分离,那就肯定会遇到cros跨域请求难题,可以设置一个BaseHandler,然后继承即可. class BaseHandler(tornado.web.RequestHan ...
- Attention 和self-attention
1.Attention 最先出自于Bengio团队一篇论文:NEURAL MACHINE TRANSLATION BY JOINTLY LEARNING TO ALIGN AND TRANSLATE ...
- Pipe——高性能IO(三)
Pipelines可以替换掉那些丑陋的封装(kludge).变通(workaround)或妥协(compromise)——用一个在框架中设计优雅的专门的解决方案. 敢肯定,下面所覆盖的那些痛点,对于那 ...
- atom 在Ubuntu 18.04 上安装及基本使用
前记: Atom 是github专门为程序员推出的一个跨平台文本编辑器.具有简洁和直观的图形用户界面,并有很多有趣的特点:支持CSS,HTML,JavaScript等网页编程语言.它支持宏,自动完成分 ...
- 几种常见的css布局_l流体布局、圣杯布局、双飞翼布局
1.流体布局: <!DOCTYPE html><html> <head> <meta charset="utf-8"> <ti ...
- jmeter 中使用正则表达式提取依赖参数
1:登录接口 这里有一个实际的登录接口,在响应中返回了一串token,如下图 那么我们在接下来的接口-经验库列表中,就必须带入这一串token,否则响应报错,如下图所示 如何获取登录的口令呢?这 ...
- Java 后台请求第三方系统接口详解
//调用第三方系统接口 PrintWriter out = null; BufferedReader in = null; JSONObject jsonObject = null; Closeabl ...