动态点分治总结
动态点分治总结
下面是伟大の分割线!
上面是伟大の分割线!
废话
再开一坑。
刷几道题来填。
才刷两题,慢慢补吧。。。。
(这玩意是真的神,调死你
警告:这篇文章中的代码都很丑陋!
下面是伟大の分割线!
上面是伟大の分割线!
思想
前置技能:点分治。
动态点分治就是带修改的点分治。
如果每次单点修改之后重新点分治一遍,被影响到的节点最多\(\log_2n\)个。
然后就有了动态点分治。。。。
点分树
我也不知道这个叫什么反正就是一颗新树。。。
构建方法大概就是点分治solve的时候顺便搞出,它就是solve时的搜索树(?)
可以证明那玩意深度是严格\(\log_2n\)的。
如果修改一个点,只需在对应点分树上修改(暴跳父亲,慢慢修改)
查询也可以暴跳父亲,但有些题不用
下面是伟大の分割线!
上面是伟大の分割线!
例题
cogs2036 捉迷藏
查询最长链。
要维护三种堆= =不看题解写不出= = = = = = = = =
(其实应该是multiset= =但是能用堆来模拟)
首先每个点维护一个堆1,是子树到这个点的距离。(“子树”是点分树,“距离”是原树上的距离)
再维护一个堆2,是所有子树的堆1堆顶
再全局维护一个堆3,是所有点堆2的最大和次大(这里要讨论一下,如果这个点是黑色的,少了的元素用0补上;如果是白色的堆又没有两个元素,就是0)
真•奇丑无比
// It is made by XZZ
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
#include<vector>
#define il inline
#define rg register
#define vd void
#define sta static
typedef long long ll;
using namespace std;
il int gi(){
rg int x=0,f=1;rg char ch=getchar();
while(ch<'0'||ch>'9')f=ch=='-'?-1:f,ch=getchar();
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x*f;
}
const int maxn=100001;
#define queue priority_queue
struct Queue{
queue<int>que,del;
il int siz(){return que.size()-del.size();}
il int top(){
if(siz()<1)return 0;
while(!del.empty()&&que.top()==del.top())que.pop(),del.pop();
return que.top();
}
il vd pop(int x){del.push(x);}
il vd push(int x){que.push(x);}
};
int n,q,fir[maxn],dis[maxn<<1],nxt[maxn<<1],col[maxn],dep[maxn],id;
il vd link(int x,int y){nxt[++id]=fir[x],fir[x]=id,dis[id]=y;}
Queue que[maxn],Que[maxn],QUE;
int siz[maxn],f[maxn],rt,vis[maxn],sum,FAQ[maxn];
il vd getrt(int x,int FA){
f[x]=0;siz[x]=1;
for(int i=fir[x];i;i=nxt[i]){
if(vis[dis[i]]||FA==dis[i])continue;
getrt(dis[i],x);
siz[x]+=siz[dis[i]];
f[x]=max(f[x],siz[dis[i]]);
}
f[x]=max(f[x],sum-siz[x]);
if(f[x]<f[rt])rt=x;
}
il vd Getrt(int x,int _sum){sum=_sum,rt=0,f[0]=2e9,getrt(x,-1);}
vector<int>S[maxn];int Root;
il vd solve(int x){
vis[x]=1;
for(int i=fir[x];i;i=nxt[i]){
if(vis[dis[i]])continue;
Getrt(dis[i],siz[dis[i]]);
FAQ[rt]=x;S[x].push_back(rt);
solve(rt);
}
}
int st[17][maxn];
il vd Getdep(int x,int FA=-1){
for(int i=fir[x];i;i=nxt[i]){
if(FA==dis[i])continue;
dep[dis[i]]=dep[x]+1;
st[0][dis[i]]=x;
Getdep(dis[i],x);
}
}
il int dist(int x,int y){
int ret=dep[x]+dep[y],cha=dep[x]-dep[y];
if(dep[x]<dep[y])cha=-cha,swap(x,y);
for(int i=16;~i;--i)if(cha&(1<<i))x=st[i][x];
for(int i=16;~i;--i)if(st[i][x]^st[i][y])x=st[i][x],y=st[i][y];
if(x^y)x=st[0][x];
return ret-2*dep[x];
}
il vd calc(int x,int FA,int Rt){
que[Rt].push(dist(x,FAQ[Rt]));
for(vector<int>::iterator i=S[x].begin();i!=S[x].end();++i){
if(FA==*i)continue;
calc(*i,x,Rt);
}
}
il int Top(int x){
sta int a,b,ret;
a=Que[x].top();Que[x].pop(a);
b=Que[x].top();Que[x].push(a);
if(col[x])ret=a+b;
else if(a&&b)ret=a+b;
else ret=0;
return ret;
}
il vd Solve(int x){
calc(x,-1,x);
for(vector<int>::iterator i=S[x].begin();i!=S[x].end();++i){
Solve(*i);
Que[x].push(que[*i].top());
}
QUE.push(Top(x));
}
int main(){
freopen("hide.in","r",stdin);
freopen("hide.out","w",stdout);
n=gi();int x,y,tot=n;
for(rg int i=1;i<=n;++i)col[i]=1;
for(rg int i=1;i<n;++i)x=gi(),y=gi(),link(x,y),link(y,x);
Getrt(1,n),Root=rt,solve(rt);
dep[1]=0,Getdep(1);
for(rg int i=1;i<17;++i)
for(rg int j=1;j<=n;++j)
st[i][j]=st[i-1][st[i-1][j]];
Solve(Root);
q=gi();char opt[5];
while(q--){
scanf("%s",opt);
if(opt[0]=='G'){
if(tot<2)printf("%d\n",tot-1);
else printf("%d\n",QUE.top());
}
else{
x=gi();y=1;
for(rg int i=x;i;i=FAQ[i]){
if(FAQ[i])QUE.pop(Top(FAQ[i]));
if(FAQ[i])Que[FAQ[i]].pop(que[i].top());
col[x]?que[i].pop(dist(FAQ[i],x)):que[i].push(dist(FAQ[i],x));
if(FAQ[i])Que[FAQ[i]].push(que[i].top());
if(FAQ[i])QUE.push(Top(FAQ[i]));
}
QUE.pop(Top(x));
if(col[x])--tot;else++tot;
col[x]^=1;
QUE.push(Top(x));
}
}
return 0;
}
bzoj3730 震波
每个点维护两颗线段树。。。这不看题解咋搞
第一颗存子树对这个点的贡献,下标是子树的点到这个点的距离,存的值是这些点的权值和
第二颗存子树对父亲的贡献,下标是到父亲的距离,存的是这些点的权值和
剩下都看题解写的。。。。。。
// It is made by XZZ
#include<cstdio>
#include<algorithm>
#include<cmath>
#define il inline
#define rg register
#define vd void
#define sta static
using namespace std;
il int gi(){
rg int x=0,f=1;rg char ch=getchar();
while(ch<'0'||ch>'9')f=ch=='-'?-1:f,ch=getchar();
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x*f;
}
const int maxn=100001,maxm=maxn<<1;
int n,m,lg,val[maxn];
typedef const int& cni;
namespace sgt{
const int maxd=20000000;
int index,root1[maxn],root2[maxn],ls[maxd],rs[maxd],sum[maxd];
#define mid ((l+r)>>1)
il vd update(int&x,int l,int r,cni p,cni k){
if(!x)x=++index;sum[x]+=k;
if(l==r)return;
if(p<=mid)update(ls[x],l,mid,p,k);
else update(rs[x],mid+1,r,p,k);
}
il int query(cni x,int l,int r,cni R){
if(!sum[x]||R<l)return 0;
if(r<=R)return sum[x];
return query(ls[x],l,mid,R)+query(rs[x],mid+1,r,R);
}
}
namespace Divide{
int fir[maxn],dis[maxm],nxt[maxm],id,rt;
il vd link(cni x,cni y){nxt[++id]=fir[x],fir[x]=id,dis[id]=y;}
namespace SLPF{
int dep[maxn],fa[maxn],siz[maxn],top[maxn],son[maxn];
il vd DFS(cni x){
siz[x]=1;
for(int i=fir[x];i;i=nxt[i])
if(dis[i]^fa[x]){
dep[dis[i]]=dep[x]+1,fa[dis[i]]=x;
DFS(dis[i]);
siz[x]+=siz[dis[i]];
if(siz[dis[i]]>siz[son[x]])son[x]=dis[i];
}
}
il vd DFS2(cni x,cni tp){
top[x]=tp;
if(son[x])DFS2(son[x],tp);
for(int i=fir[x];i;i=nxt[i])
if((dis[i]^fa[x])&&(dis[i]^son[x]))
DFS2(dis[i],dis[i]);
}
il int dist(int x,int y){
int ret=dep[x]+dep[y];
while(top[x]^top[y])
if(dep[top[x]]>dep[top[y]])x=fa[top[x]];
else y=fa[top[y]];
if(dep[y]<dep[x])x=y;
return ret-dep[x]*2;
}
}
namespace DFZ{
int f[maxn],siz[maxn],FAQ[maxn],sum,vis[maxn];
il vd getrt(cni x,cni FA){
f[x]=0,siz[x]=1;
for(int i=fir[x];i;i=nxt[i]){
if(FA==dis[i]||vis[dis[i]])continue;
getrt(dis[i],x);
siz[x]+=siz[dis[i]],f[x]=max(f[x],siz[dis[i]]);
}
f[x]=max(f[x],sum-siz[x]);
if(f[x]<f[rt])rt=x;
}
il vd Getrt(cni x,cni _sum){f[0]=2e9,sum=_sum,rt=0,getrt(x,-1);}
il vd Build(int x){
vis[x]=1;
for(int i=fir[x];i;i=nxt[i]){
if(vis[dis[i]])continue;
Getrt(dis[i],siz[dis[i]]);
FAQ[rt]=x;Build(rt);
}
}
}
il int Query(int x,int k){
int ret=sgt::query(sgt::root1[x],1,n,k+1),yyb=0;
for(int i=x;DFZ::FAQ[i];i=DFZ::FAQ[i]){
yyb=SLPF::dist(x,DFZ::FAQ[i]);
ret+=sgt::query(sgt::root1[DFZ::FAQ[i]],1,n,k-yyb+1);
ret-=sgt::query(sgt::root2[i],1,n,k-yyb+1);
}
return ret;
}
il vd Update(int x,int y){
sgt::update(sgt::root1[x],1,n,1,y);int yyb=0;
for(int i=x;DFZ::FAQ[i];i=DFZ::FAQ[i]){
yyb=SLPF::dist(x,DFZ::FAQ[i]);
sgt::update(sgt::root1[DFZ::FAQ[i]],1,n,yyb+1,y);
sgt::update(sgt::root2[i],1,n,yyb+1,y);
}
}
il vd Prepare(){
DFZ::Getrt(1,n);
SLPF::DFS(1),SLPF::DFS2(1,1);
DFZ::Build(rt);
for(rg int i=1;i<=n;++i)Update(i,val[i]);
}
}
int main(){
#ifdef xzz
freopen("orz.in","r",stdin);
freopen("orz.out","w",stdout);
#endif
int opt,u,v,lst=0;
n=gi(),m=gi();lg=log2(n);
for(rg int i=1;i<=n;++i)val[i]=gi();
for(rg int i=1;i<n;++i)u=gi(),v=gi(),Divide::link(u,v),Divide::link(v,u);
Divide::Prepare();
while(m--){
opt=gi(),u=gi(),v=gi();
#ifdef ONLINE_JUDGE
u^=lst,v^=lst;
#endif
if(opt==0)lst=Divide::Query(u,v),printf("%d\n",lst);
else Divide::Update(u,v-val[u]),val[u]=v;
}
return 0;
}
bzoj4372 烁烁的游戏
我™放弃了。。。
哪天想起来了再补吧
// It is made by XZZ
#include<cstdio>
#include<algorithm>
#define il inline
#define rg register
#define vd void
#define sta static
typedef long long ll;
il int gi(){
rg int x=0,f=1;rg char ch=getchar();
while(ch<'0'||ch>'9')f=ch=='-'?-1:f,ch=getchar();
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x*f;
}
const int maxn=maxm;
typedef const int& ci;
int n,m;
namespace sgt{
int maxd=2e7;
int ls[maxd],rs[maxd],sum[maxd],idx;
#define mid ((l+r)>>1)
il vd update(int&x,int l,int r,ci p,ci k){
if(!x)x=++idx;sum[x]+=k;
if(l==r)return;
if(mid<p)update(rs[x],mid+1,r,p,k);
else update(ls[x],l,mid,p,k);
}
il int query(ci x,int l,int r,ci L,ci R){
if(!sum[x]||R<l||r<L)return 0;
if(L<=l&&r<=R)return sum[x];
return query(ls[x],l,mid,L,R)+query(rs[x],mid+1,r,L,R);
}
#undef mid
}
namespace Tree{
int fir[maxn],nxt[maxn<<1],dis[maxn<<1],idx;
il vd link(ci x,ci y){nxt[++id]=fir[x],fir[x]=id,dis[id]=y;}
namespace SLPF{
int root[maxn],root2[maxn],siz[maxn],dep[maxn],fa[maxn],son[maxn],top[maxn];
il vd dfs(ci x){
siz[x]=1;
for(int i=fir[x];i;i=nxt[i]){
if(fa[x]==i)continue;
fa[dis[i]]=x;
dep[dis[i]]=dep[x]+1;
dfs(dis[i]);
if(siz[dis[i]]>siz[son[x]])son[x]=dis[i];
}
}
il vd dfs2(ci x,ci tp){
top[x]=tp;
if(son[x])dfs2(son[x],tp);
for(int i=fir[x];i;i=nxt[i]){
if(fa[x]==i||son[x]==i)continue;
dfs2(dis[i],dis[i]);
}
}
il int dist(int x,int y){
int ret=dep[x]+dep[y];
while(top[x]^top[y])
if(dep[top[x]]>dep[top[y]])x=fa[top[x]];
else y=fa[top[y]];
if(dep[x]>dep[y])x=y;
return ret-dep[x]*2;
}
}namespace DFZ{
int siz[maxn],f[maxn],rt,sum;bool vis[maxn];
il vd getrt(ci x,ci FA){
siz[x]=1,f[x]=0;
for(int i=fir[x];i;i=nxt[i]){
if(FA==dis[i]||vis[dis[i]])continue;
getrt(dis[i],x);
siz[x]+=siz[dis[i]];
f[x]=max(f[x],siz[dis[i]]);
}
f[x]=max(f[x],sum-siz[dis[i]]);
if(f[x]<f[rt])rt=x;
}
il vd Getrt(ci x,ci _sum){f[0]=2e9,rt=0,sum=_sum,getrt(x,-1);}
il vd build(ci x){
vis[x]=1;
for(int i=fir[x];i;i=nxt[i]){
if(vis[dis[i]])continue;
Getrt(dis[i],siz[dis[i]]);
FAQ[rt]=x;
build(rt);
}
}
}
il vd prepare(){
int u,v;
for(rg int i=1;i<n;++i)u=gi(),v=gi(),link(u,v),link(v,u);
DFZ::Getrt(1,n),DFZ::build(DFZ::rt);
SLPF::dfs(1),SLPF::dfs2(1);
}
il vd Update(int x,int d,int w){
sgt::update(root[x],1,n,d+1,w);
for(rg int i=FAQ[x];FAQ[i];i=FAQ[i]){
int dst=SLPF::dist(x,FAQ[i]);
sgt::update(sgt::root[FAQ[i]],1,n,1,w);
sgt::update(sgt::root2[i],1,n,1,w);
sgt::update(sgt::root[FAQ[i]],1,n,dst+2,-w);
sgt::update(sgt::root2[i],1,n,dst+2,-w);
}
}
il int Query(int x){
int ret=sgt::query(root[x],);
}
}
int main(){
freopen("orz.in","r",stdin);
freopen("orz.out","w",stdout);
n=gi(),m=gi();
return 0;
}
博主是蒟蒻,有问题请指出,谢谢!
本博客中博文均为原创,未经博主允许请勿随意转载,谢谢。
本博客中博文均为原创,未经博主允许请勿随意转载,谢谢。