P3384 树剖模板
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
typedef unsigned long long ull;
int const maxn=100110,maxm=100110;
int n,q,p,root;
//*******以下为存图部分********
struct E
{
int to,next;
E(int to=0,int next=0):
to(to),next(next){}
}e[maxn<<1];
int head[maxn],cnt2;
void rem()
{
memset(head,-1,sizeof(head));
}
void add(int u,int v)
{
e[++cnt2]=(E){v,head[u]};
head[u]=cnt2;
}
//*********以下为剖树部分**********
int dep[maxn],fa[maxn],size[maxn],hson[maxn];
int id[maxn],top[maxn],w[maxn],val[maxn],tot;
int pre_dfs(int u,int f)
{
dep[u]=dep[f]+1;
fa[u]=f;
size[u]=1;
int maxson=-1;
for(int i=head[u];i!=-1;i=e[i].next)
{
int v=e[i].to;
if(v==f)
continue;
size[u]+=pre_dfs(v,u);
if(maxson<size[v])
{
hson[u]=v;
maxson=size[v];
}
}
return size[u];
}
void mark_dfs(int u,int topf)
{
id[u]=++tot;
top[u]=topf;
w[tot]=val[u];
// if(!hson[u])
if(size[u]==1)
return;
mark_dfs(hson[u],topf);
for(int i=head[u];i!=-1;i=e[i].next)
{
int v=e[i].to;
if(!id[v])
mark_dfs(v,v);
//轻边的链顶自然是轻儿子
}
}
//********以下为线段树部分********
int cnt=1;
//根节点
struct Tree
{
int lc,rc,sum,tag;
}a[maxn<<1];
void pushup(int u)
{
a[u].sum=a[a[u].lc].sum+a[a[u].rc].sum;
}
void build(int u,int l,int r)
{
if(l==r)
{
a[u].sum=w[l];
//l为序列的点
return;
}
int mid=(l+r)/2;
a[u].lc=++cnt;
build(a[u].lc,l,mid);
a[u].rc=++cnt;
build(a[u].rc,mid+1,r);
pushup(u);
}
void pushdown(int u,int l,int r)
{
int mid=(l+r)/2;
int tag=a[u].tag,lc=a[u].lc,rc=a[u].rc;
a[lc].sum=(a[lc].sum%p+((mid-l+1)%p*tag%p)%p)%p;
a[lc].tag=(a[lc].tag%p+tag%p)%p;
a[rc].sum=(a[rc].sum%p+((r-mid)%p*tag%p)%p)%p;
a[rc].tag=(a[rc].tag%p+tag%p)%p;
a[u].tag=0;
}
void update(int u,int l,int r,int ll,int rr,int dlt)
{
if(l==ll&&r==rr)
{
a[u].sum=(a[u].sum%p+(dlt%p*(r-l+1)%p)%p)%p;
//Navie
a[u].tag=(a[u].tag%p+dlt%p)%p;
return;
}
pushdown(u,l,r);
int mid=(l+r)/2;
if(mid>=rr)
//喜闻乐见的错误
update(a[u].lc,l,mid,ll,rr,dlt);
else if(mid<ll)
update(a[u].rc,mid+1,r,ll,rr,dlt);
else
{
update(a[u].lc,l,mid,ll,mid,dlt);
update(a[u].rc,mid+1,r,mid+1,rr,dlt);
}
pushup(u);
}
int query(int u,int l,int r,int ll,int rr)
{
if(l==ll&&r==rr)
return a[u].sum;
pushdown(u,l,r);
int mid=(l+r)/2;
return mid>=ll&&mid<rr?(query(a[u].lc,l,mid,ll,mid)%p+query(a[u].rc,mid+1,r,mid+1,rr)%p)%p:(mid<ll?query(a[u].rc,mid+1,r,ll,rr)%p:query(a[u].lc,l,mid,ll,rr)%p);
}
/*
int query(int u,int l,int r,int ll,int rr)
{
if(l==ll&&r==rr)
return a[u].sum;
pushdown(u,l,r);
int mid=(l+r)/2;
if(mid>=ll&&mid<rr)
return (query(a[u].lc,l,mid,ll,mid)%p+query(a[u].rc,mid+1,r,mid+1,rr)%p)%p;
return mid<ll?query(a[u].rc,mid+1,r,ll,rr)%p:query(a[u].lc,l,mid,ll,rr)%p;
}
*/
//********以下为线段树维护树链信息*********
void TL_update(int x,int y,int dlt)
{
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]])
std::swap(x,y);
update(1,1,n,id[top[x]],id[x],dlt);
x=fa[top[x]];
}
if(dep[x]>dep[y])
std::swap(x,y);
update(1,1,n,id[x],id[y],dlt);
}
int TL_query(int x,int y)
{
int ans=0;
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]])
std::swap(x,y);
ans=(ans%p+query(1,1,n,id[top[x]],id[x]))%p;
//dep比较小的为左区间
x=fa[top[x]];
}
if(dep[x]>dep[y])
std::swap(x,y);
ans=(ans%p+query(1,1,n,id[x],id[y]))%p;
return ans;
}
//********以下为线段树维护子树信息********
void Tr_update(int x,int dlt)
{
update(1,1,n,id[x],id[x]+size[x]-1,dlt);
//一直不懂
}
int Tr_query(int x)
{
return query(1,1,n,id[x],id[x]+size[x]-1);
}
//**********以下为读入部分***********
void read()
{
scanf("%d%d%d%d",&n,&q,&root,&p);
for(int i=1;i<=n;i++)
scanf("%d",&val[i]),val[i]%=p;
for(int x,y,i=1;i<n;i++)
scanf("%d%d",&x,&y),add(x,y),add(y,x);
}
int main()
{
memset(head,-1,sizeof(head));
read();
dep[root]=-1,
pre_dfs(root,0);
mark_dfs(root,root);
build(1,1,n);
for(int op,x,y,i=1;i<=q;i++)
{
scanf("%d%d",&op,&x);
if(op==4)
{
printf("%d\n",Tr_query(x));
continue;
}
scanf("%d",&y);
if(op==1)
{
int z;scanf("%d",&z);
TL_update(x,y,z);
}
else if(op==2)
printf("%d\n",TL_query(x,y));
else
Tr_update(x,y);
}
return 0;
}
P3376 树剖求LCA
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
typedef unsigned long long ull;
int const maxn=500100,maxm=500100;
int n,q,root;
//******************************************
struct E
{
int to,next;
E(int to=0,int next=0):
to(to),next(next){}
}e[maxm<<1];
int head[maxn],cnt;
void add(int u,int v)
{
e[++cnt]=(E){v,head[u]};
head[u]=cnt;
}
//******************************************
int dep[maxn],size[maxn],hson[maxn],fa[maxn];
int top[maxn],tot;
int pre_dfs(int u,int f)
{
dep[u]=dep[f]+1;
fa[u]=f;
size[u]=1;
int maxson=-1;
for(int i=head[u];i;i=e[i].next)
{
int v=e[i].to;
if(v==f)
continue;
size[u]+=pre_dfs(v,u);
if(maxson<size[v])
{
maxson=size[v];
hson[u]=v;
}
}
return size[u];
}
void mark_dfs(int u,int topf)
{
top[u]=topf;
if(size[u]==1)
return;
mark_dfs(hson[u],topf);
for(int i=head[u];i;i=e[i].next)
{
int v=e[i].to;
if(v==fa[u])
continue;
if(v!=hson[u])
mark_dfs(v,v);
}
}
//*****************************************
int LCA(int x,int y)
{
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]])
std::swap(x,y);
x=fa[top[x]];
}
if(dep[x]>dep[y])
std::swap(x,y);
return x;
}
int main()
{
scanf("%d%d%d",&n,&q,&root);
for(int x,y,i=1;i<n;i++)
scanf("%d%d",&x,&y),add(x,y),add(y,x);
dep[root]=-1;
pre_dfs(root,0);
mark_dfs(root,root);
for(int x,y,i=1;i<=q;i++)
{
scanf("%d%d",&x,&y);
printf("%d\n",LCA(x,y));
}
return 0;
}
P1967 货车运输
!这道题要好好说说了,喵的坑了我一上午
虽说一看就是道最大生成树+树剖维护链上最小值的水题,但介于这是我打的第一道树剖题,还是出了不少岔子
注意事项
1、这题需要化边权为点权,显然是要将边权下放到儿子上,因为对于一个点来说父亲只有一个,儿子可能有多个
2、根节点要特殊处理!,因为没有深度比根更小的点,所以根不会也不能对答案产生影响,对于这道题来说,需要赋一个极大值
3、该图不保证联通,所以要建最大生成森林,而且要以多个点为根节点跑dfs
4、不要把并查集的fa1[]和维护树点父亲的fa2[]搞混!!!
5、最大的坑点!当我以为可以线段树暴力查询的时候,我惊奇的发现待查询的两个点的LCA会对结果产生影响,这是因为每个点的点权实际上存的是连向父亲边的权,因此我们需要把LCA的点权给干掉,因为压根就不会经过那条边,具体操作为把LCA的id+1,因为LCA的深度小,作为查询的左区间
6、哈哈哈哈哈哈你以为这样就结束了?LCA的深度一定小么?当两条轻链都向上跳的时候有可能会跳到同一个点,需要特判
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
typedef unsigned long long ull;
int const maxn=500100,maxm=500100,inf=0x1f1f1f1f;
int n,m,q,num,root[maxn],cur;
//*******************************************
struct E
{
int to,next,w;
E(int to=0,int next=0,int w=0):
to(to),next(next),w(w){}
}e[maxn<<1];
int head[maxn],cnt;
void add(int u,int v,int w)
{
e[++cnt]=(E){v,head[u],w};
head[u]=cnt;
// printf("%d%d,",v,u);
}
//*******************************************
int dep[maxn],size[maxn],fa[maxn],hson[maxn];
int top[maxn],id[maxn],w[maxn],val[maxn],tot;
int pre_dfs(int u,int ff)
{
dep[u]=dep[ff]+1;
fa[u]=ff;
size[u]=1;
int maxson=-1;
for(int i=head[u];i!=-1;i=e[i].next)
{
int v=e[i].to,w=e[i].w;
if(v==ff)
continue;
val[v]=w;
size[u]+=pre_dfs(v,u);
if(maxson<size[v])
{
maxson=size[v];
hson[u]=v;
}
}
return size[u];
}
void mark_dfs(int u,int topf)
{
id[u]=++tot;
top[u]=topf;
w[tot]=val[u];
if(size[u]==1)
return;
mark_dfs(hson[u],topf);
for(int i=head[u];i!=-1;i=e[i].next)
{
int v=e[i].to;
if(!id[v])
mark_dfs(v,v);
}
}
//*******************************************
struct Tree
{
int lc,rc,min;
}a[maxn];
int t=1;
void build(int u,int l,int r)
{
if(l==r)
{
a[u].min=w[l];
return;
}
int mid=(l+r)/2;
a[u].lc=++t;build(a[u].lc,l,mid);
a[u].rc=++t;build(a[u].rc,mid+1,r);
a[u].min=std::min(a[a[u].lc].min,a[a[u].rc].min);
}
int query(int u,int l,int r,int ll,int rr)
{
if(l==ll&&r==rr)
return a[u].min;
int mid=(l+r)/2;
return mid>=ll&&mid<rr?std::min(query(a[u].lc,l,mid,ll,mid),query(a[u].rc,mid+1,r,mid+1,rr)):(mid>=rr?query(a[u].lc,l,mid,ll,rr):query(a[u].rc,mid+1,r,ll,rr));
//ll是待修改区间,l是当前处理到的区间,不要混淆!
}
//*******************************************
int TL_query(int x,int y)
{
int ans=inf;
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]])
std::swap(x,y);
ans=std::min(ans,query(1,1,n,id[top[x]],id[x]));
x=fa[top[x]];
}
if(dep[x]>dep[y])
std::swap(x,y);
if(x!=y)
//深坑!
ans=std::min(ans,query(1,1,n,id[x]+1,id[y]));
return ans;
}
//*******************************************
struct RE
{
int u,v,w;
int operator <(const RE &b)const
{
return w>b.w;
}
}ee[maxm];
int f[maxn];
int find(int x)
{
return x==f[x]?x:f[x]=find(f[x]);
}
void kruskal()
{
for(int i=1;i<=n;i++)
f[i]=i;
std::sort(ee+1,ee+1+m);
for(int i=1;i<=m;i++)
{
int w=ee[i].w,u=ee[i].u,v=ee[i].v,
fu=find(u),
fv=find(v);
// printf("%d %d,,,\n",fu,fv);
if(fu==fv)
continue;
f[fu]=fv;
// printf("!%d %d:%d\n",u,v,w);
add(u,v,w),add(v,u,w);
}
}
//*******************************************
int main()
{
memset(head,-1,sizeof(head));
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
scanf("%d%d%d",&ee[i].u,&ee[i].v,&ee[i].w);
kruskal();
// /*
for(int i=1;i<=n;i++)
if(!size[i])
dep[i]=-1,pre_dfs(i,0),val[i]=inf,root[++cur]=i;
for(int i=1;i<=cur;i++)
mark_dfs(root[i],root[i]);
// for(int i=1;i<=n;i++)
// printf("!%d %d\n",i,id[i]);
build(1,1,n);
// */
scanf("%d",&q);
for(int x,y,i=1;i<=q;i++)
{
scanf("%d%d",&x,&y);
if(find(x)!=find(y))
{
printf("-1\n");
continue;
}
printf("%d\n",TL_query(x,y));
}
return 0;
}
P3128 Max Flow
感觉我是真的蠢…
明知道是求区间最值和求和完全弄混了…
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
typedef unsigned long long ull;
int const maxn=50100,maxm=50100,inf=0x1f1f1f1f;
int n,q;
// ********************************
struct E
{
int to,next;
E(int to=0,int next=0):
to(to),next(next){}
}e[maxn<<1];
int head[maxn],cnt;
void add(int u,int v)
{
e[++cnt]=(E){v,head[u]};
head[u]=cnt;
}
//*********************************
int dep[maxn],size[maxn],fa[maxn],hson[maxn];
int id[maxn],top[maxn],tot;
int pre_dfs(int u,int f)
{
dep[u]=dep[f]+1;
fa[u]=f;
size[u]=1;
int maxson=-1;
for(int i=head[u];i;i=e[i].next)
{
int v=e[i].to;
if(v==f)
continue;
size[u]+=pre_dfs(v,u);
if(size[v]>maxson)
{
maxson=size[v];
hson[u]=v;
}
}
return size[u];
}
void mark_dfs(int u,int topf)
{
id[u]=++tot;
top[u]=topf;
if(size[u]==1)
return;
mark_dfs(hson[u],topf);
for(int i=head[u];i;i=e[i].next)
{
int v=e[i].to;
if(!id[v])
mark_dfs(v,v);
}
}
//*********************************
struct Tree
{
int lc,rc,max,tag;
}a[maxn<<1];
int t=1;
void pushup(int u)
{
a[u].max=std::max(a[a[u].lc].max,a[a[u].rc].max);
}
void pushdown(int u,int l,int r)
{
int tag=a[u].tag,lc=a[u].lc,rc=a[u].rc;
a[lc].max+=tag,a[lc].tag+=tag;
a[rc].max+=tag,a[rc].tag+=tag;
a[u].tag=0;
}
void build(int u,int l,int r)
{
if(l==r)
return;
int mid=(l+r)/2;
a[u].lc=++t;build(a[u].lc,l,mid);
a[u].rc=++t;build(a[u].rc,mid+1,r);
}
void update(int u,int l,int r,int ll,int rr)
{
if(l==ll&&r==rr)
{
a[u].max++;
a[u].tag++;
// printf("!!!%d %d %d\n",l,r,a[u].max);
return;
}
pushdown(u,l,r);
int mid=(l+r)/2;
if(mid>=rr)
update(a[u].lc,l,mid,ll,rr);
else if(mid<ll)
update(a[u].rc,mid+1,r,ll,rr);
else
{
update(a[u].lc,l,mid,ll,mid);
update(a[u].rc,mid+1,r,mid+1,rr);
}
pushup(u);
}
//*********************************
void TL_update(int x,int y)
{
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]])
std::swap(x,y);
update(1,1,n,id[top[x]],id[x]);
x=fa[top[x]];
}
if(dep[x]>dep[y])
std::swap(x,y);
update(1,1,n,id[x],id[y]);
}
//*********************************
int main()
{
// freopen("in.in","r",stdin);
scanf("%d%d",&n,&q);
for(int x,y,i=1;i<n;i++)
scanf("%d%d",&x,&y),add(x,y),add(y,x);
dep[1]=-1,pre_dfs(1,0);
// puts("shit\n");
mark_dfs(1,1);
// for(int i=1;i<=n;i++)
// printf("!!!%d %d\n",i,id[i]);
build(1,1,n);
for(int x,y,i=1;i<=q;i++)
scanf("%d%d",&x,&y),/*printf("id:%d %d\n",id[x],id[y]),*/TL_update(x,y);
printf("%d",a[1].max);
return 0;
}
P2146 软件包管理器
都说这题比较水,其实还是有点东西的,调了一下午…
才不是因为两个三目运算符嵌套太长了一直没看到错…
题目疯狂明示,n-1个关系画出来就是一棵树
用1表示已安装,0表示未安装,
就会发现安装就是对从根到当前节点的树链操作,卸载就是对当前节点的子树操作,具体操作是区间覆盖区间查询
很朴素的思路是在修改前后各查询一次,差值就是答案
然而仔细一想,对子树的查询得到的(1)已安装的个数,已经是答案了,用深度减去对树链的查询就是(0)未安装的个数
以下为坑点:
1、tag的初值为-1,因为0在本题有意义
2、tag只有在不等于-1的时候才能向下传
3、区间覆盖就是把+=改为=
4、习惯问题,节点右移
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
typedef unsigned long long ull;
int const maxn=1001100,maxm=1001100,inf=0x1f1f1f1f;
int n,q;
//***************************
struct E
{
int to,next;
E(int to=0,int next=0):
to(to),next(next){}
}e[maxn];
int head[maxn],cnt;
void add(int u,int v)
{
e[++cnt]=(E){v,head[u]};
head[u]=cnt;
}
//***************************
int dep[maxn],size[maxn],hson[maxn],fa[maxn];
int id[maxn],top[maxn],tot;
int pre_dfs(int u,int f)
{
dep[u]=dep[f]+1;
size[u]=1;
fa[u]=f;
int maxson=-1;
for(int i=head[u];i;i=e[i].next)
{
int v=e[i].to;
if(v==f)
continue;
size[u]+=pre_dfs(v,u);
if(maxson<size[v])
{
maxson=size[v];
hson[u]=v;
}
}
return size[u];
}
void mark_dfs(int u,int topf)
{
id[u]=++tot;
top[u]=topf;
if(size[u]==1)
return;
mark_dfs(hson[u],topf);
for(int i=head[u];i;i=e[i].next)
{
int v=e[i].to;
if(!id[v])
mark_dfs(v,v);
}
}
//***************************
struct Tree
{
int lc,rc,sum,tag;
}a[maxn<<1];
int t=1;
void pushup(int u)
{
a[u].sum=a[a[u].lc].sum+a[a[u].rc].sum;
}
void pushdown(int u,int l,int r)
{
int mid=(l+r)/2,
lc=a[u].lc,rc=a[u].rc,tag=a[u].tag;
a[lc].sum=tag*(mid-l+1);a[lc].tag=tag;
a[rc].sum=tag*(r-mid);a[rc].tag=tag;
a[u].tag=-1;
}
void build(int u,int l,int r)
{
if(l==r)
{
a[u].tag=-1;
return;
}
int mid=(l+r)/2;
a[u].lc=++t;build(a[u].lc,l,mid);
a[u].rc=++t;build(a[u].rc,mid+1,r);
}
void update(int u,int l,int r,int ll,int rr,int end)
{
if(l==ll&&r==rr)
{
// printf("!%d %d %d\n",l,r,end);
a[u].sum=end*(r-l+1);
a[u].tag=end;
return;
}
if(a[u].tag!=-1)
pushdown(u,l,r);
int mid=(l+r)/2;
if(rr<=mid)
update(a[u].lc,l,mid,ll,rr,end);
else if(ll>mid)
update(a[u].rc,mid+1,r,ll,rr,end);
else
update(a[u].lc,l,mid,ll,mid,end),update(a[u].rc,mid+1,r,mid+1,rr,end);
pushup(u);
}
int query(int u,int l,int r,int ll,int rr)
{
if(l==ll&&r==rr)
return a[u].sum;
if(a[u].tag!=-1)
pushdown(u,l,r);
int mid=(l+r)/2;
return mid>=ll&&mid<rr?query(a[u].lc,l,mid,ll,mid)+query(a[u].rc,mid+1,r,mid+1,rr):(mid>=rr?query(a[u].lc,l,mid,ll,rr):query(a[u].rc,mid+1,r,ll,rr));
}
//***************************
int TL_query(int x)
{
int ans=dep[x],y=1;
while(top[x]!=top[y])
{
// printf("!!!%d %d\n",id[top[x]],id[x]);
ans-=query(1,1,n,id[top[x]],id[x]);
update(1,1,n,id[top[x]],id[x],1);
// printf("??????%d %d %d\n",id[x],id[top[x]],query(1,1,n,id[top[x]],id[x]));
// printf("~~~%d\n",query(1,1,n,7,7));
x=fa[top[x]];
}
std::swap(x,y);
ans-=query(1,1,n,id[x],id[y]);
// printf("~~~%d\n",query(1,1,n,id[x],id[y]));
update(1,1,n,id[x],id[y],1);
// printf("!!!!!!%d %d %d\n",id[x],id[y],query(1,1,n,id[x],id[y]));
return ans;
}
int Tr_query(int x)
{
int ans=query(1,1,n,id[x],id[x]+size[x]-1);
update(1,1,n,id[x],id[x]+size[x]-1,0);
return ans;
}
int main()
{
scanf("%d",&n);
for(int x,i=1;i<n;i++)
scanf("%d",&x),add(x+1,i+1);
pre_dfs(1,0);
mark_dfs(1,1);
build(1,1,n);
// for(int i=1;i<=n;i++)
// printf("!!!%d %d:%d %d\n",i,id[i],dep[i],top[i]);
scanf("%d",&q);
for(int x,i=1;i<=q;i++)
{
std::string op;
std::cin>>op;
scanf("%d",&x);x++;
// printf("%c\n",op[0]);
if(op[0]=='i')
printf("%d\n",TL_query(x));
else
printf("%d\n",Tr_query(x));
}
return 0;
}