[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 ...
随机推荐
- MySQL批量SQL插入各种性能优化
对于一些数据量较大的系统.数据库面临的问题除了查询效率低下,还有就是数据入库时间长.特别像报表系统,每天花费在数据导入上的时间可能会长达几个小时或十几个小时之久.因此.优化数据库插入性能是非常有意义的 ...
- 冒泡排序Vs直接选择排序
什么是排序?为什么要使用排序?事实上我们生活中处处都用到了排序.拿字典来说,如今,我们要在字典中查找某个字(已经知道这个字的读音),首先.我们须要依据这个字的读音,找到它所所在文件夹中的位置,然后依据 ...
- NoSQL数据库:Redis内存使用优化与存储
Redis常用数据类型 Redis最为常用的数据类型主要有以下五种: ●String ●Hash ●List ●Set ●Sorted set 在具体描述这几种数据类型之前,我们先通过一张图了解下Re ...
- LeetCode208:Implement Trie (Prefix Tree)
Implement a trie with insert, search, and startsWith methods. Note: You may assume that all inputs a ...
- android自定义dialog中点击listview的item事件关闭dialog
import android.app.Activity; import android.app.AlertDialog; import android.app.AlertDialog.Builder; ...
- vim gvim技巧大全(9)(转载)
vim gvim技巧大全(9) 2 用命令}移动到这个段落的底部,标记为b3 输入命令:'a,'b move来移动文本.老版本的Vi编辑器不能很好的来处理多文件.但是Vim在处理多文件上却显得优秀得多 ...
- Java 发送短信
这是一个调用sms接口发短信的程序,支持同时发送的短信量并不是很大,只作为学习使用(当然如果你想内部使用也行) 源码:package com; import org.apache.commons.ht ...
- Django day15 (二) csrf的 跨站请求伪造 与 局部禁用 , 局部使用
一: csrf 的跨站请求伪造 二: csrf 的局部禁用 , 局部使用
- LocalDateTime相关处理,得到零点以及24点值,最近五分钟点位,与Date互转,时间格式
最近一直使用LocalDateTime,老是忘记怎么转换,仅此记录一下 import java.time.Instant; import java.time.LocalDateTime; import ...
- 模拟Queue(wait/notify)
BlockingQueue:顾名思义,首先它是一个队列,并且支持阻塞的机制,阻塞的放入和得到数据.我们要实现LinkedBlockingQueue下面的两个方法put和take. put(anObje ...