[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 ...
随机推荐
- jQuery和CSS3炫酷button点击波特效
这是一款效果很炫酷的jQuery和CSS3炫酷button点击波特效.该特效当用户在菜单button上点击的时候.从鼠标点击的点開始,会有一道光波以改点为原点向外辐射的动画效果,很绚丽. 在线演示:h ...
- CentOS-6.5安装配置Tomcat-7
https://my.oschina.net/u/593517/blog/304483 http://blog.csdn.net/lgh0824/article/details/51194116 摘要 ...
- luogu3157 动态逆序对
题目大意 给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数. 思路 #include <cstdio> #include <c ...
- codeforces 931E Logical Expression dp
time limit per test 3 seconds memory limit per test 256 megabytes input standard input output standa ...
- 【BZOJ 1398】 Necklace
[题目链接] https://www.lydsy.com/JudgeOnline/problem.php?id=1398 [算法] 最小表示法 [代码] #include<bits/stdc++ ...
- ubuntu 12.10 禁用触摸板
1. 打开终端,输入 sudo rmmod psmouse 禁用触摸板,输入 sudo modprobe psmouse 恢复触摸板 2.syndaemon -i 10 -d >/dev/nul ...
- hdu4405Aeroplane chess(概率与期望dp)
Aeroplane chess Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)T ...
- CVTE面经
神一般的面试经历.也算面了不少公司,没见过这种面试. 一面:三个同学对应一个面试官,同一个问题依次作答. 1.为什么投递这个岗位? 答:blablabla... 2.最难忘的成功项目? 答:blabl ...
- 计算某个时间段(2017-10-01 2017-12-01)内svn更新文件的MD5
#!/bin/sh svn up svn log -v -r {$1}:{$2} | grep / | grep -v xxx | sort -f -u | uniq | awk -F 'xxxx' ...
- MySQL学习笔记之右连接
MySQL的右连接 #右连接,以右表为基表 select course.stuid,course.stuname,sex,course,city from class1 right join cour ...