BZOJ 2286 树链剖分+DFS序+虚树+树形DP

第一次学习虚树,就是把无关的点去掉。S里维护一条链即可。

  1 #include <iostream>
  2 #include <cstring>
  3 #include <cstdio>
  4 #include <algorithm>
  5 #define LL long long
  6 using namespace std;
  7 const LL Maxm=501000;
  8 const LL Maxn=250100;
  9 const LL Inf=1e60;
 10 struct Node {LL to,next,w;}edge[Maxm],edge2[Maxm];
 11 LL head[Maxn],head2[Maxn],dep[Maxn],H[Maxn],mark[Maxn],size[Maxn];
 12 LL top[Maxn],father[Maxn],f[Maxn],S[Maxn],mn[Maxn];
 13 LL cnt1,cnt2,tot,n,u,v,w,tp,m,K;
 14 bool vis[Maxn];
 15 inline void Add(LL u,LL v,LL w)
 16 {edge[cnt1].to=v;edge[cnt1].next=head[u];edge[cnt1].w=w;head[u]=cnt1++;
 17 edge[cnt1].to=u;edge[cnt1].next=head[v];edge[cnt1].w=w;head[v]=cnt1++;}
 18 inline void Add2(LL u,LL v)
 19 {if (u==v) return; edge2[cnt2].to=v;edge2[cnt2].next=head2[u];head2[u]=cnt2++;}
 20 inline LL Min(LL x,LL y) {return x>y?y:x;}
 21 inline void Get_Int(LL &x)
 22 {
 23     x=0;  char ch=getchar(); LL f=1;
 24     while (ch<‘0‘ || ch>‘9‘) {if (ch==‘-‘) f=-1; ch=getchar();}
 25     while (ch>=‘0‘ && ch<=‘9‘) {x=x*10+ch-‘0‘; ch=getchar();} x*=f;
 26 }
 27 inline void Put_Int(LL x)
 28 {
 29     char ch[20];  LL top=0;
 30     if (x==0) ch[++top]=‘0‘;
 31     while (x) ch[++top]=x%10+‘0‘,x/=10;
 32     while (top) putchar(ch[top--]); putchar(‘\n‘);
 33 }
 34 //================================================
 35 void Dfs1(LL u)
 36 {
 37     mark[u]=++tot;vis[u]=true; size[u]=1;
 38     for (LL i=head[u];i!=-1;i=edge[i].next)
 39         if (!vis[edge[i].to])
 40         {
 41             dep[edge[i].to]=dep[u]+1;
 42             father[edge[i].to]=u;
 43             mn[edge[i].to]=Min(mn[u],edge[i].w);
 44             Dfs1(edge[i].to);
 45             size[u]+=size[edge[i].to];
 46         }
 47 }
 48 void Dfs2(LL u,LL chain)
 49 {
 50     top[u]=chain; vis[u]=true; LL k=0;
 51     for (int i=head[u];i!=-1;i=edge[i].next)
 52         if (!vis[edge[i].to] && (size[edge[i].to]>size[k] || k==0)) k=edge[i].to;
 53     if (k==0) return;
 54     Dfs2(k,chain);
 55     for (int i=head[u];i!=-1;i=edge[i].next)
 56         if (!vis[edge[i].to] && i!=k) Dfs2(edge[i].to,edge[i].to);
 57 }
 58 inline LL Lca(LL u,LL v)
 59 {
 60     while (true)
 61     {
 62         if (top[u]==top[v]) return dep[u]>dep[v]?v:u;
 63         if (dep[top[u]]>dep[top[v]]) u=father[top[u]];
 64         else v=father[top[v]];
 65     }
 66 }
 67 //=============================================================
 68 inline bool cmp(LL x,LL y) {return mark[x]<mark[y];}
 69 void Dp(LL u)
 70 {
 71
 72     vis[u]=true; f[u]=mn[u]; LL ret=0;
 73     for (int i=head2[u];i!=-1;i=edge2[i].next)
 74     {
 75         Dp(edge2[i].to);
 76         ret+=f[edge2[i].to];
 77     }
 78     head2[u]=-1;
 79     if (ret) f[u]=Min(f[u],ret);
 80 }
 81 void Solve()
 82 {
 83     Get_Int(K);
 84     for (int i=1;i<=K;i++) Get_Int(H[i]);
 85     sort(H+1,H+K+1,cmp);
 86     tp=tot=0; H[++tot]=H[1];
 87     for (int i=2;i<=K;i++)
 88         if (Lca(H[tot],H[i])!=H[tot]) H[++tot]=H[i];
 89     cnt2=0;
 90     S[++tp]=1;
 91     for (int i=1;i<=tot;i++)
 92     {
 93         LL u=H[i],f=Lca(u,S[tp]);
 94         while (true)
 95         {
 96             if (dep[f]>=dep[S[tp-1]])
 97             {
 98                 Add2(f,S[tp--]);
 99                 if (S[tp]!=f) S[++tp]=f;
100                 break;
101             }
102             Add2(S[tp-1],S[tp]); tp--;
103         }
104         if (S[tp]!=u) S[++tp]=u;
105     }
106     while (--tp) Add2(S[tp],S[tp+1]);
107     Dp(1);
108     Put_Int(f[1]);
109 }
110 int main()
111 {
112     Get_Int(n);
113     memset(head,-1,sizeof(head));cnt1=0;
114     for (int i=1;i<n;i++)
115     {
116         Get_Int(u),Get_Int(v),Get_Int(w);
117         Add(u,v,w),Add(v,u,w);
118     }
119
120     father[1]=1; dep[1]=1; tot=0; mn[1]=Inf;
121     memset(vis,false,sizeof(vis));Dfs1(1);
122     memset(vis,false,sizeof(vis));Dfs2(1,1);
123     memset(head2,-1,sizeof(head2));
124     Get_Int(m);
125     for (int i=1;i<=m;i++) Solve();
126     return 0;
127 }

C++

时间: 2024-12-24 11:48:04

BZOJ 2286 树链剖分+DFS序+虚树+树形DP的相关文章

BZOJ 2819 Nim 树链剖分/DFS序+LCA+树状数组

题意:给定一棵树,每个节点是一堆石子,给定两种操作: 1.改变x号节点的石子数量 2.用从x到y的路径上的所有堆石子玩一次Nim游戏,询问是否有必胜策略 Nim游戏有必胜策略的充要条件是所有堆的石子数异或起来不为零 这题首先一看就是树链剖分 然后题目很善良地告诉我们深搜会爆栈 于是我们可以选择广搜版的树链剖分 BFS序从左到右是深搜,从右到左是回溯,一遍BFS就够 单点修改区间查询还可以套用ZKW线段树 不过这题其实不用这么麻烦 有更简单的办法 详见 http://dzy493941464.is

codeforces 343D Water Tree 树链剖分 dfs序 线段树 set

题目链接 这道题主要是要考虑到同一棵子树中dfs序是连续的 然后我就直接上树剖了... 1 #include<bits/stdc++.h> 2 using namespace std; 3 const int MAXN=600005; 4 5 struct Node 6 { 7 int l,r; 8 int value; 9 void init() 10 { 11 l=r=value=0; 12 } 13 }tree[4*MAXN]; 14 vector<int>nei[MAXN]

BZOJ 2243:染色(树链剖分+区间合并线段树)

[SDOI2011]染色Description给定一棵有n个节点的无根树和m个操作,操作有2类:1.将节点a到节点b路径上所有点都染成颜色c:2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”.“222”和“1”.请你写一个程序依次完成这m个操作.Input第一行包含2个整数n和m,分别表示节点数和操作数:第二行包含n个正整数表示n个节点的初始颜色下面 行每行包含两个整数x和y,表示x和y之间有一条无向边.下面 行每行描述一个操作:“C

BZOJ 2243: [SDOI2011]染色 树链剖分 倍增lca 线段树

2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/problem.php?id=2243 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”.“222”和“1”. 请你写

【BZOJ4515】游戏,树链剖分+永久化标记线段树维护线段信息(李超线段树)

Time:2016.05.10 Author:xiaoyimi 转载注明出处谢谢 传送门 思路: 李超线段树 一开始听faebdc讲,并没有听的很懂ww 后来找到良心博文啊有木有 折越 首先可以把修改转换一下,因为那个dis非常不爽.显然s~t的路径有s~lca和lca~t组成.令d[x]表示x的深度,对于s~lca上面的点,修改的值相当于a*(d[s]-d[x])+b=-a*d[x]+(b-a*d[s]),lca~t上面的点的值相当于a*(d[s]+d[x]-2*d[lca])+b=a*d[x

Water Tree(树链剖分+dfs时间戳)

Water Tree http://codeforces.com/problemset/problem/343/D time limit per test 4 seconds memory limit per test 256 megabytes input standard input output standard output Mad scientist Mike has constructed a rooted tree, which consists of n vertices. Ea

【树链剖分(区间线段树)】BZOJ4196-[NOI2015]软件包管理

[题目大意] 如果软件包A依赖软件包B,那么安装软件包A以前,必须先安装软件包B.同时,如果想要卸载软件包B,则必须卸载软件包A.而且,由于你之前的工作,除0号软件包以外,在你的管理器当中的软件包都会依赖一个且仅一个软件包,而0号软件包不依赖任何一个软件包.依赖关系不存在环.求出在安装和卸载某个软件包时,实际上会改变多少个软件包的安装状态(即安装操作会安装多少个未安装的软件包,或卸载操作会卸载多少个已安装的软件包.(注意,安装一个已安装的软件包,或卸载一个未安装的软件包,都不会改变任何软件包的安

【树链剖分】【线段树】bzoj3626 [LNOI2014]LCA

引用题解: http://blog.csdn.net/popoqqq/article/details/38823457 题目大意: 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1.设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先.有q次询问,每次询问给出l r z,求sigma_{l<=i<=r}dep[LCA(i,z)].(即,求在[l,r]区间内的每个节点i与z的最近公共祖先的深度之和) 这题看见了直接卡壳...然后

【块状树】【树链剖分】【线段树】bzoj3531 [Sdoi2014]旅行

离线后以宗教为第一关键字,操作时间为第二关键字排序. <法一>块状树,线下ac,线上tle…… #include<cstdio> #include<cmath> #include<algorithm> #include<cstring> #include<queue> using namespace std; queue<int>q; int f,c; inline void R(int &x){ c=0;f=1;