树链剖分

线段树动态开点+树链剖分BZOJ4999

点点圈 提交于 2019-12-03 02:48:36
以每个一个颜色开一颗线段树,内部以dfs序作为线段树节点,权值代表出现次数,维护线段树区间和 #include<iostream> #include<stdio.h> #include<string.h> #include<algorithm> #include<map> using namespace std; const int maxn = 2e5+6; struct edge{ int next,to; }e[maxn*2]; struct node{ int l,r; int w; }tree[maxn*50]; int head[maxn],siz[maxn],top[maxn],son[maxn]; int d[maxn],fa[maxn],id[maxn],rk[maxn],dfn[maxn],c[maxn]; int n,m,uu,vv,tot,cnt; int rt[maxn]; map<int,int>p; void add(int x,int y){ e[++cnt].next=head[x]; e[cnt].to=y; head[x]=cnt; } void dfs1(int u,int f,int depth){ d[u]=depth; fa[u]=f; siz[u]=1; for (int i=head[u];i;i=e[i].next){ int v

BZOJ.5404.party(树链剖分 bitset Hall定理)

匿名 (未验证) 提交于 2019-12-03 00:41:02
题目链接 只有指向父节点的单向道路,所以c个人肯定在LCA处汇合。那么就成了有c条到LCA的路径,求最大的x,满足能从c条路径中各选出x个数,且它们不同。 先要维护一条路径的数的种类数,可以树剖+每条链维护一个bitset解决。用vector一条链加一个bitset,SDOI R2现场测过我记得空间还不算特别大。。当然本题数字只有1000种,一个点开一个bitset没问题。最后合并时还要通过线段树。 假设答案是x,那么c个人都要从可选特产中不重复地选x个,把每个人拆成x个点就是一个二分图完备匹配。 由Hall定理,左边集合(c*x个点)任意一个子集与右边集合相邻的点数应不小于该子集大小。因为每个人的x个点的连边相同(复制了x次),所以对每个人只需判断x个都选的子集。 c很小,2^c枚举子集。与右边集合相邻点数就是选中人的bitset的并的大小size。设枚举了s个人,那么每次枚举有 \(x*s \leq size\) 。 所以 \(x = \min\{\frac{size}{s}\}\) 。 好慢啊。。垫底了。。 学了下fwrite,然并软。 //220140kb 7192ms #include <cstdio> #include <cctype> #include <bitset> #include <algorithm> //#define gc() getchar()

LCA 树链剖分

匿名 (未验证) 提交于 2019-12-03 00:40:02
// LCA // 树链剖分 在线 #include<iostream> #include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <algorithm> using namespace std; int n,m,root,cnt,head[ 500001 ]; int hvyson[ 500001 ],fa[ 500001 ],siz[ 500001 ],dep[ 500001 ],top[ 500001 ]; struct uio{ int to,next; }edge[ 1000001 ]; void add( int x, int y) { edge[ ++cnt].next= head[x]; edge[cnt].to = y; head[x] = cnt; } void dfs1( int x, int f, int depth) { dep[x] = depth; fa[x] = f; siz[x] = 1 ; int maxson=- 1 ; for ( int i=head[x];i;i= edge[i].next) { int y= edge[i].to; if (y== f) continue ; dfs1(y,x,depth + 1 ); siz[x]

洛谷P3384 【模板】树链剖分

匿名 (未验证) 提交于 2019-12-02 23:55:01
题目传送门 #include <iostream> #include <cstdio> #include <vector> #define maxn 100005 using namespace std ; typedef long long ll ; struct T { int data , next ; } e [ maxn << 1 ]; int top [ maxn ], son [ maxn ], size [ maxn ], depth [ maxn ], data [ maxn ], fa [ maxn ]; int head [ maxn ], cnt ; vector <int> vec ; int p ; struct node { int l , r ; ll sum ; ll lazy ; } tree [ maxn << 2 ]; void add ( int x , int y ) { ++ cnt ; e [ cnt ]. data = y ; e [ cnt ]. next = head [ x ]; head [ x ] = cnt ; } void dfs1 ( int x ) { size [ x ] = 1 ; for ( int i = head [ x ]; i != 0 ; i = e [ i ]. next ){ int r = e

[ZJOI2008]树的统计 树链剖分

匿名 (未验证) 提交于 2019-12-02 23:52:01
题面 裸树剖,一个线段树同时维护 sum 和 max 就好了。 庆祝半小时1A此题。 #include <cstdio> #include <algorithm> #define MAXN 30003 #define sl (x<<1) #define sr (x<<1|1) using namespace std; int head[MAXN],nxt[MAXN*2],vv[MAXN*2],tot; inline void add_edge(int u, int v){ vv[++tot]=v; nxt[tot]=head[u]; head[u]=tot; } int fa[MAXN],dep[MAXN],sz[MAXN],mxs[MAXN]; void dfs1(int u, int f){ dep[u]=dep[f]+1; fa[u]=f; sz[u]=1; int mxsz=-1; for(int i=head[u];i;i=nxt[i]){ int v=vv[i]; if(v==f) continue; dfs1(v, u); sz[u]+=sz[v]; if(mxsz<sz[v]){ mxsz=sz[v]; mxs[u]=v; } } } int w[MAXN],wnew[MAXN]; int topf[MAXN],idx[MAXN],cnt; void dfs2

树链剖分 模板

匿名 (未验证) 提交于 2019-12-02 23:47:01
修改与查询整个子树 修改与查询路径 #include<bits/stdc++.h> using namespace std; //input by bxd #define rep(i,a,b) for(int i=(a);i<=(b);i++) #define repp(i,a,b) for(int i=(a);i>=(b);--i) #define RI(n) scanf("%d",&(n)) #define RII(n,m) scanf("%d%d",&n,&m) #define RIII(n,m,k) scanf("%d%d%d",&n,&m,&k) #define RS(s) scanf("%s",s); #define ll long long #define see(x) (cerr<<(#x)<<'='<<(x)<<endl) #define pb push_back #define inf 0x3f3f3f3f #define CLR(A,v) memset(A,v,sizeof A) #define lson l,m,pos<<1 #define rson m+1,r,pos<<1|1 typedef pair<int,int>pii; ////////////////////////////////// const int N=2e6+10; const int

树链剖分

对着背影说爱祢 提交于 2019-12-02 21:55:12
我终于码了树链剖分,别人半年前学会的东西我终于入门辣!!! 先放全代码: 1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<cmath> 5 #define MAXN 30010 6 using namespace std; 7 const int INF=(1<<30); 8 struct rr{ 9 int nt,to; 10 }bl[MAXN<<1];int hd[MAXN],itot; 11 void addedge(int x,int y){ 12 bl[++itot]=(rr){hd[x],y}; 13 hd[x]=itot; 14 return ; 15 } 16 int n; 17 int w[MAXN]; 18 int son[MAXN],L[MAXN],top[MAXN],sz[MAXN]; 19 int fat[MAXN]; 20 int sd[MAXN]; 21 int num=0; 22 int line[MAXN];//dfs序上的某一个位置具体是哪个节点 23 void dfs1(int u,int fa){ 24 sz[u]=1;fat[u]=fa; 25 for(int i=hd[u],y;i;i=bl[i].nt) 26 if(bl[i].to!=fa){

可爱的树链剖分(染色)

青春壹個敷衍的年華 提交于 2019-12-02 16:47:46
可爱的树链剖分(染色) 这道题 就是 一道 普通的! 树链剖分+线段树覆盖 注意一下两个线段树合并的时候 如果 \(lval(node<<1|1)==rval(node<<1)\) 相当于这两个线段树的相邻的数字数相同的 那么合并时的 \(tot\) \(sum\) 应该 -- 所以说这道题有什么细节吗 我感觉是没有的 然而我调了一下午+晚上两个小时 (再次感谢人帅心善的kma小哥哥) (话说为什么他有这么多女朋友,而我还是单身呢) 不 我有萌德 #include <cstdio> #include <iostream> #include <algorithm> #include <cstring> #define int long long using namespace std; const int maxn=1e6+10; int read(){ int x=0,f=1;char ch=getchar(); while(ch<'0' || ch>'9'){if(ch=='-') f=-1;ch=getchar();} while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}; return x*f; } int n,m,color[maxn],fir[maxn<<1],nxt[maxn<<1],to[maxn<<1],tot

树链剖分

狂风中的少年 提交于 2019-12-02 10:58:28
“在一棵树上进行路径的修改、求极值、求和”乍一看只要线段树就能轻松解决,实际上,仅凭线段树是不能搞定它的。我们需要用到一种貌似高级的复杂算法——树链剖分。 树链剖分是将一棵树按照特殊的dfs序划分成链,从而使 树上任意一条链最多被划分为log(n)段, 同时保持的dfs序对子树操作的便利。 什么是树链剖分 树链剖分,它可以对一棵树进行轻重链剖分后用数据结构来维护每条重链。 比如下面这个问题:假设每个点有一个点权。如何把一棵树上的两个点uu,vv之间的简单路径上的所有点的点权增加dd? 这就是树链剖分能够解决的的一个基本问题。 接下来介绍一下树链剖分的详细过程。 轻重链剖分 树链剖分的第一步就是将一棵树进行轻重链剖分。 这一步决定了整个树链剖分的时间复杂度 。 引入几个概念: size[u]:以u为根的子树大小 wson[u]:在u的儿子中size值最大的那一个,称作uu的重儿子 dfn[u]:每个点的dfs序号。pre[tot],如果dfn[u]=tot,则pre[tot]=u 重链:指每个点与它的重儿子之间的连边(u—wson[u]) 轻链:在所有边中不是重的其他边 看图: 如上图,每一个带红点的点就是轻儿子;每一条加粗的的边就是重链,没有加粗的就是轻边。比如说对于点2,那么 wson[2]=6,size[2]=5,size[wson[u]]=size[6]=3。 dfn[u]

HOJ-Contest194-Problem-D 树链剖分

天涯浪子 提交于 2019-12-02 06:53:29
题意概述: 现给出一棵N个结点的树,每个结点可能存在两种状态:0/1,所有结点的初始状态为0。现在进行M次操作,每一次都翻转两个结点的状态。每次操作后,询问:对状态为1的结点之间两两匹配,对匹配点对之间距离进行求和,和的最小值。(显然始终有偶数个状态为1的点) 数据范围: N<=100000,M<=100000,time limit:3s,memory limit:512mb. 分析: 首先考虑最直接的暴力做法。题目要求进行点对的匹配,那么就直接手动搜索所有可能的匹配情况,然后把和最小的方案找出来。直接粘代码,复杂度O(M*sqrt(N!))。 然后考虑比较高效的做法。由于对搜索的做法想不出比较好的优化方法,所以说应该换其他方法,那么需要考虑这个问题的一些特性。首先从简单的情况开始考虑:1、只有两个状态为1的点(以下简称1点),直接匹配;2、有4个1点: 上图是一种比较一般的情况,其中每条边的长度大于等于0。假如我们认为a,b,e,f是我们描述的4个1点,那么显然E(a,c),E(b,c),E(d,e),E(d,f)的长度大于0。由于没有指定长度的相对大小,所以实际上只有两种情况:(1)匹配(a,b),(e,f),那么距离和为l(a,c)+l(b,c)+l(d,e)+l(d,f);(2)匹配(a,e),(b,f),那么距离和为l(a,c)+l(b,c)+l(d,e)+l(d,f)