[SDFZOJ]1069:树上统计
神题。。。std丑的不行。
我们可以发现i->i+1的边被覆盖过i×(n-i)次。
因为以1->i为左端点,以i+1->n的为右端点,i->i+1都将被覆盖这么多次。
然后从1->n扫,i->i+1的路径上的边的贡献就是n×(n-i)×边数-路径上的标记和×(n-i)。因为标记的意义就是它最后一次被覆盖是什么时候。如果tag是k,那么之前1->k为左端点就都统计过这个了。所以就要减标记和×(n-i)(由上面的话可知是n-i次),然后在路径上上打大小为i的tag。具体实现就是树剖+线段树。(我的树剖是直接粘的板子。。。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<stack>
#include<algorithm>
#include<cstdlib>
using namespace std;
const int N=;
int n,m,r,a[N],head[N],ecnt,siz[N],fa[N],dep[N],son[N],dfn1[N],dfn2[N],top[N],ncnt,rnk[N];
struct Segtree {
int sum,lazy,l,r;
} seg[N<<];
struct Edge {
int to,nxt;
} e[N<<];
inline void pushup(int x) {
seg[x].sum=seg[x<<].sum+seg[x<<|].sum; }
inline void add(int bg,int ed){
e[++ecnt].nxt=head[bg];
e[ecnt].to=ed;
head[bg]=ecnt;
}
void build(int L,int R,int x) {
seg[x].l=L,seg[x].r=R;
if(L==R) {
seg[x].sum=a[rnk[L]];
return;
}
int mid=(L+R)>>;
build(L,mid,x<<);
build(mid+,R,x<<|);
pushup(x);
} inline void pushdown(int x) {
if(seg[x].lazy) {
if(seg[x].l!=seg[x].r) {
seg[x<<].sum=seg[x].lazy*(seg[x<<].r-seg[x<<].l+); seg[x<<|].sum=(seg[x].lazy)*(seg[x<<|].r-seg[x<<|].l+); seg[x<<].lazy=seg[x].lazy; seg[x<<|].lazy=seg[x].lazy; }
seg[x].lazy=;
}
}
void update(int L,int R,int x,int c) {
if(R<seg[x].l||L>seg[x].r)return;
if(L<=seg[x].l&&seg[x].r<=R) {
seg[x].lazy=c;
seg[x].sum=(seg[x].r-seg[x].l+)*c; return;
}
pushdown(x);
update(L,R,x<<,c);
update(L,R,x<<|,c);
pushup(x);
}
int query(int L,int R,int x){
if(L>seg[x].r||R<seg[x].l)return ;
if(L<=seg[x].l&&seg[x].r<=R){
return seg[x].sum;
}
pushdown(x);
return (query(L,R,x<<)+query(L,R,x<<|));
}
void dfs1(int x){
siz[x]=;
for(int i=head[x];i;i=e[i].nxt){
int v=e[i].to;
if(fa[x]==v) continue;
fa[v]=x;
dep[v]=dep[x]+;
dfs1(v);
siz[x]+=siz[v];
if(siz[v]>siz[son[x]]) son[x]=v;
}
}
void dfs2(int x,int qtop){
top[x]=qtop;dfn1[x]=++ncnt;
rnk[dfn1[x]]=x;
if(son[x]) dfs2(son[x],qtop);
for(int i=head[x];i;i=e[i].nxt){
int v=e[i].to;
if(v==fa[x]||v==son[x]) continue;
dfs2(v,v);
}
dfn2[x]=ncnt;
}
void add_v(int x,int y,int z){
int f1=top[x],f2=top[y];
while(f1!=f2){
if(dep[f1]<dep[f2]) swap(f1,f2),swap(x,y);
update(dfn1[f1],dfn1[x],,z);
x=fa[f1],f1=top[x];
}
if(dep[x]>dep[y]) update(dfn1[y],dfn1[x],,z);
else update(dfn1[x],dfn1[y],,z);
}
inline int query_path(int x,int y){
int f1=top[x],f2=top[y],ans=;
while(f1!=f2){
if(dep[f1]<dep[f2]) swap(f1,f2),swap(x,y);
ans+=query(dfn1[f1],dfn1[x],);
x=fa[f1],f1=top[x];
}
if(dep[x]>dep[y]) ans+=query(dfn1[y],dfn1[x],);
else ans+=query(dfn1[x],dfn1[y],);
return ans;
}
inline int LCA(int x,int y){
while(top[x]!=top[y])
(dep[top[x]]>=dep[top[y]])? x=fa[top[x]]:y=fa[top[y]];;
return dep[x]<dep[y]?x:y;
}
signed main() {
cin>>n;
int u,v,b,c;
for(int i=;i<n;i++){
scanf("%d%d",&u,&v);
add(u,v);
add(v,u);
}
dfs1();
dfs2(,);
build(,n,);
long long ans=;
for(int i=,lca;i<n;i++) {
lca=LCA(i,i+);
ans+=(1ll*(dep[i]-dep[lca]+dep[i+]-dep[lca])*(n-i)*i-1ll*(query_path(i,i+)-query_path(lca,lca))*(n-i));
int tp=query_path(lca,lca);
add_v(i,i+,i);add_v(lca,lca,tp);
}
cout<<ans<<endl;
return ;
}
树上统计
[SDFZOJ]1069:树上统计的更多相关文章
- [洛谷U40581]树上统计treecnt
[洛谷U40581]树上统计treecnt 题目大意: 给定一棵\(n(n\le10^5)\)个点的树. 定义\(Tree[l,r]\)表示为了使得\(l\sim r\)号点两两连通,最少需要选择的边 ...
- NOIP2016天天爱跑步 题解报告【lca+树上统计(桶)】
题目描述 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.«天天爱跑步»是一个养成类游戏,需要玩家每天按时上线,完成打卡任务. 这个游戏的地图可以看作一一棵包含 nn个 ...
- Luogu P2664 树上游戏 dfs+树上统计
题目: P2664 树上游戏 分析: 本来是练习点分治的时候看到了这道题.无意中发现题解中有一种方法可以O(N)解决这道题,就去膜拜了一下. 这个方法是,假如对于某一种颜色,将所有这种颜色的点全部删去 ...
- HDU 6043:Colorful Tree(树上统计所有路径总颜色数)***
题目链接 题意 给出一棵有n个结点的树,每个结点有一个颜色,问在这棵树的所有路径中,每条路径的颜色数求和是多少. 思路 求每种颜色的贡献可以转化为总的和减去每种颜色在哪些路径上没有出现的贡献,一个颜色 ...
- 【csp模拟赛6】树上统计-启发式合并,线段树合并
30%:暴力 40%:枚举L,R从L~n枚举,R每增大一个,更新需要的边(bfs实现)60%:枚举每条边, 计算每条边的贡献另外20%的数据:枚举每条边,计算每条边的贡献100%:对于每一条边统计 有 ...
- 树上统计treecnt(dsu on tree 并查集 正难则反)
题目链接 dalao们怎么都写的线段树合并啊.. dsu跑的好慢. \(Description\) 给定一棵\(n(n\leq 10^5)\)个点的树. 定义\(Tree[L,R]\)表示为了使得\( ...
- 【CF500D】New Year Santa Network(树上统计)
..]of longint; z:..]of extended; n,i,m,tot,x1:longint; ans,fenmu,y1:extended; procedure add(a,b:long ...
- [hdu5593 ZYB's Tree] 树上统计
题意:给1棵N(≤500,000)个节点的树,每条边边权为1,求距离每个点距离不超过K(K≤10)的点的个数的xor和. 思路:由于K很小,可以考虑把距离作为状态的一部分,然后研究父子之间状态的联系. ...
- EOJ 306 树上问题
题解: 因为w大于1,所以,题意就是,有多少(x,z),存在x到z的路径上,有一个x<y<z的y w没用的其实. 树上路径问题,有什么方法吗? 1.树链剖分.这个主要方便处理修改操作. 2 ...
随机推荐
- Linux内核剖析 之 进程简单介绍
1.概念 1.1 什么是进程? 进程是程序运行的一个实例.能够看作充分描写叙述程序已经运行到何种程度的数据结构的汇集. 从内核观点看.进程的目的就是担当分配系统资源(CPU时间,内存 ...
- 浅谈 System.Decimal 结构
引言 我们知道,Microsoft .NET Framework 中的 System.Decimal 结构(在 C# 语言中等价于 decimal keyword)用来表示十进制数,范围从 -(296 ...
- springmvc学习笔记(10)-springmvc注解开发之商品改动功能
springmvc学习笔记(10)-springmvc注解开发之商品改动功能 标签: springmvc springmvc学习笔记10-springmvc注解开发之商品改动功能 需求 开发mappe ...
- KD树——k=1时就是BST,里面的数学原理还是有不明白的地方,为啥方差划分?
Kd-Tree,即K-dimensional tree,是一棵二叉树,树中存储的是一些K维数据.在一个K维数据集合上构建一棵Kd-Tree代表了对该K维数据集合构成的K维空间的一个划分,即树中的每个结 ...
- 迭代,IDA*
1.codevs1288 题意:对于一个分数a/b(a!=1),将它表示为1/x + 1/y + 1/z ……的形式,x,y,z……互不相同 多解取加数少的,加数相同时,取最小的分数最大的. 思路:经 ...
- thinkphp 上传多张图片
tp3.23 没有找到同时上传多张图片 手册有讲过:http://www.kancloud.cn/manual/thinkphp/1876 其实可以通过,多张图片多次上传来到达效果 hmlt: < ...
- java的random生成某个范围内的随机数
import java.util.Random; /** * @author HP * @date 2019/4/16 */ public class randomTest { public stat ...
- npm搭建React项目
转自:http://blog.csdn.net/u012859720/article/details/70597119 要想使用npm,首先安装Node.js 一.安装全局包 $ npm instal ...
- python 线程池和锁
一.死锁现象与递归锁 锁:Lock线程安全,多线程操作时,内部会让所有线程排队处理.如:list/dict/Queue 线程不安全 + 人 => 排队处理. import thre ...
- D - Replacement
Problem description Little Petya very much likes arrays consisting of n integers, where each of them ...