动态点分治:bzoj 3730,bzoj 1095
来源:互联网 发布:域名收录查询 编辑:程序博客网 时间:2024/05/14 13:10
总结一下动态点分治的模板。。。
对于一个树,把它点分的同时记录每个点的所有父亲(logn个)并记录点距其父亲的距离。
具体实现就是dfs的时候fa[x][++dep[x]]=u,dis[x][dep[x]]=d;
BZOJ1095:
您需要写一个程序支持反转点的颜色,求距离最远的黑色点对的距离。
解析:在每个点u存一个堆st记录该子树(分治中的)中点到fa[u]的距离再存一个堆son记录他所有儿子的st.top()
最后再用一个总的堆维护直径。
修改的时候就从点u开始向上爬,将fa[u]的son $#%^% 一下,再修改u的st。
#include<queue>#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>#define inf (1<<30)#define maxn 100100using namespace std;struct set{ priority_queue<int>pq,_del; void push(int x){ pq.push(x); } void del(int x){ _del.push(x); } void pop(){ pq.pop(); } int top(){ while(_del.size()&&pq.top()==_del.top())pq.pop(),_del.pop(); return pq.top(); } int size(){ return pq.size()-_del.size(); } int maxlen(){ int a=top(); pop(); int b=top(); return push(a),a+b; }}st[maxn],all,son[maxn];struct edge{ int r,nxt;}e[maxn<<1];int b[20],light=0,col[maxn],head[maxn],esz,fa[maxn][18],dep[maxn],mn,rt,vis[maxn],s[maxn],dis[maxn][18],n,m,sz;void addedge(int u,int v){ e[++esz].r=v;e[esz].nxt=head[u];head[u]=esz; e[++esz].r=u;e[esz].nxt=head[v];head[v]=esz;}void init(int u,int f){ sz++; for(int t=head[u];t;t=e[t].nxt) if(e[t].r!=f&&!vis[e[t].r])init(e[t].r,u);}void getroot(int u,int f){ int mxsize=0;s[u]=1; for(int t=head[u];t;t=e[t].nxt) if(e[t].r!=f&&!vis[e[t].r]){ getroot(e[t].r,u),s[u]+=s[e[t].r]; mxsize=max(mxsize,s[e[t].r]); } mxsize=max(mxsize,sz-s[u]); if(mn>mxsize)mn=mxsize,rt=u;}void build(int u,int f,int x,int d){ for(int t=head[u];t;t=e[t].nxt) if(e[t].r!=f&&!vis[e[t].r]){ fa[e[t].r][++dep[e[t].r]]=x; dis[e[t].r][dep[e[t].r]]=d+1; build(e[t].r,u,x,d+1); }}void calc(int u,int f,int x){ if(u==x)st[x].push(dis[u][dep[u]]); else st[x].push(dis[u][dep[u]-1]);//printf("[%d->%d:%d,%d]\n",fa[x][dep[x]],u,dis[u][dep[u]-1],fa[u][dep[u]]); for(int t=head[u];t;t=e[t].nxt) if(e[t].r!=f&&!vis[e[t].r])calc(e[t].r,u,x);}void solve(int u){ mn=inf,sz=0,init(u,0),getroot(u,0); vis[u=rt]=true,build(u,0,u,0);calc(u,0,u); son[u].push(0);//printf("[%d]\n",u); for(int t=head[u];t;t=e[t].nxt) if(!vis[e[t].r])solve(e[t].r);}void change(int i){ if(col[i]){ light--; if(son[i].size()>1)all.del(son[i].maxlen()); son[i].del(0); if(son[i].size()>1)all.push(son[i].maxlen()); for(int j=dep[i]+1;j>=2;j--){ int nw=fa[i][j],pre=fa[i][j-1];// if(fa[nw][dep[nw]]!=pre)exit(-1); if(son[pre].size()>1)all.del(son[pre].maxlen());//printf("[ok:%d]",son[pre].maxlen());// printf("<%d>",st[nw].top()+1); if(st[nw].size())son[pre].del(st[nw].top());// printf("<%d>",st[nw].top()); st[nw].del(dis[i][j-1]);// printf("<%d,%d>",dis[i][j-1],st[nw].top()); if(st[nw].size())son[pre].push(st[nw].top()); if(son[pre].size()>1)all.push(son[pre].maxlen());//printf("[ok:%d]",son[pre].maxlen()); } } else { light++; if(son[i].size()>1)all.del(son[i].maxlen()); son[i].push(0); if(son[i].size()>1)all.push(son[i].maxlen()); for(int j=dep[i]+1;j>=2;j--){ int nw=fa[i][j],pre=fa[i][j-1]; if(son[pre].size()>1)all.del(son[pre].maxlen()); if(st[nw].size())son[pre].del(st[nw].top()); st[nw].push(dis[i][j-1]); if(st[nw].size())son[pre].push(st[nw].top()); if(son[pre].size()>1)all.push(son[pre].maxlen()); } } col[i]=!col[i];}int main(){ // freopen("in.txt","r",stdin);// freopen("out.txt","w",stdout); scanf("%d",&n);light=n; for(int i=1,u,v;i<n;i++) scanf("%d%d",&u,&v),addedge(u,v); for(int i=1;i<=n;++i)col[i]=1; solve(1); for(int i=1;i<=n;++i)if(fa[i][dep[i]]&&st[i].size())son[fa[i][dep[i]]].push(st[i].top());//,printf("[%d->%d:%d]",i,fa[i][dep[i]],st[i].top()); for(int i=1;i<=n;++i)if(son[i].size()>1)all.push(son[i].maxlen());//printf("[%d:%d]",i,son[i].maxlen()); for(int i=1;i<=n;++i)fa[i][dep[i]+1]=i; scanf("%d",&m); for(int i=1,x;i<=m;++i){// printf("[%d]\n",light); char op[2];scanf("%s",op); if(op[0]=='C')scanf("%d",&x),change(x); else printf("%d\n",light>1?all.top():light-1); }}BZOJ 3730
在一片土地上有N个城市,通过N-1条无向边互相连接,形成一棵树的结构,相邻两个城市的距离为1,其中第i个城市的价值为value[i]。
不幸的是,这片土地常常发生地震,并且随着时代的发展,城市的价值也往往会发生变动。
接下来你需要在线处理M次操作:
0 x k 表示发生了一次地震,震中城市为x,影响范围为k,所有与x距离不超过k的城市都将受到影响,该次地震造成的经济损失为所有受影响城市的价值和。
1 x y 表示第x个城市的价值变成了y。
对每个点设一个树状数组bit存点到根的距离,fbit存点到跟的fa的距离,大小为树高
于是就可以容斥了:ans+=bit(k-dis)-fbit(k-dis);
修改什么的都暴力爬树就可
#include<vector> #include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>#include<sys/mman.h>#define inf (1<<30)#define maxn 100100using namespace std;struct edge{ int r,nxt;}e[maxn<<1];int rt,mn,head[maxn],key[maxn],n,m,fa[maxn][18],dep[maxn],esz,dis[maxn][18],vis[maxn],sz,s[maxn];int *bit[maxn],*fbit[maxn],size[maxn];void addedge(int u,int v){ e[++esz].r=v;e[esz].nxt=head[u];head[u]=esz; e[++esz].r=u;e[esz].nxt=head[v];head[v]=esz;}void init(int u,int f){ sz++; for(int t=head[u];t;t=e[t].nxt) if(e[t].r!=f&&!vis[e[t].r])init(e[t].r,u);}void getroot(int u,int f){ int mxsize=0; s[u]=1; for(int t=head[u];t;t=e[t].nxt) if(e[t].r!=f&&!vis[e[t].r]){ getroot(e[t].r,u),s[u]+=s[e[t].r]; if(mxsize<s[e[t].r])mxsize=s[e[t].r]; } if(mxsize<sz-s[u])mxsize=sz-s[u]; if(mn>mxsize)mn=mxsize,rt=u;}void build(int u,int f,int x,int d){ size[x]=max(size[x],d); for(int t=head[u];t;t=e[t].nxt) if(e[t].r!=f&&!vis[e[t].r]){ int v=e[t].r; fa[v][++dep[v]]=x; dis[v][dep[v]]=d+1; build(v,u,x,d+1); }}void solve(int u){ mn=inf,sz=0,init(u,0),getroot(u,0); u=rt;vis[u]=true; build(u,0,u,0); size[u]=min(sz,size[u]*2+2); bit[u]=(int*)calloc(size[u]+1,4); fbit[u]=(int*)calloc(size[u]+1,4); for(int t=head[u];t;t=e[t].nxt)if(!vis[e[t].r])solve(e[t].r);}void modify(int* bit,int lim,int x,int a){ for(;x<=lim&&x;x+=x&-x)bit[x]+=a;}void change(int i){ modify(fbit[i],size[i],dis[i][dep[i]],key[i]); for(int j=1;j<=dep[i];++j) modify(bit[fa[i][j]],size[fa[i][j]],dis[i][j],key[i]), modify(fbit[fa[i][j]],size[fa[i][j]],dis[i][j-1],key[i]);}int query(int *bit,int x){// printf("[%d]\n",x); int ans=0; for(;x;x-=x&-x)ans+=bit[x]; return ans;}int qsum(int x,int k){ int ans=query(bit[x],min(k,size[x]))+key[x]; for(int i=1;i<=dep[x];++i)if(dis[x][i]<=k) ans+=query(bit[fa[x][i]],min(size[fa[x][i]],k-dis[x][i]))+key[fa[x][i]]-query(fbit[fa[x][i+1]],min(size[fa[x][i+1]],k-dis[x][i])); return ans;}struct _i{char *p;_i(){p=(char*)mmap(NULL,10000000,PROT_READ,MAP_PRIVATE,fileno(stdin),0); }inline int operator()(){int r=0;while(*p<'0')p++;while(*p>='0')r=r*10+*(p++)-'0';return r;}}rd;int main(){ n=rd(),m=rd(); for(int i=1;i<=n;++i)key[i]=rd(); for(int i=1,u,v;i<n;++i)u=rd(),v=rd(),addedge(u,v); solve(1); for(int i=1;i<=n;++i)fa[i][dep[i]+1]=i; for(int i=1;i<=n;++i)change(i);// change(6); for(int i=1,lst=0;i<=m;++i){ int op,x,y;op=rd(),x=rd(),y=rd(); x^=lst,y^=lst; if(op==0)printf("%d\n",lst=qsum(x,y)); else key[x]=-key[x],change(x),key[x]=y,change(x); }}
0 0
- 动态点分治:bzoj 3730,bzoj 1095
- bzoj 3730: 震波 (动态点分治)
- [BZOJ]1095 捉迷藏 动态点分治(点分树)
- BZOJ 1095 ZJOI 2007 Hide 捉迷藏 动态点分治
- bzoj 1095: [ZJOI2007]Hide 捉迷藏 (动态点分治)
- bzoj 2599(点分治)
- BZOJ 4012 HNOI 2015 开店 动态点分治
- 【点分治】BZOJ 1468:Tree
- bzoj 3697(点分治)
- 【BZOJ】1468 Tree 点分治
- bzoj 1468(点分治)
- bzoj 1316(点分治)
- bzoj 2599(点分治)
- bzoj 3365(点分治)
- BZOJ 1095 Hide 捉迷藏 详解(动态点分治 堆维护)
- BZOJ 3730: 震波 动态树分治 线段树 lca
- BZOJ 1095 ZJOI2007 Hide 捉迷藏 动态树分治+堆
- 【BZOJ 1095】[ZJOI2007]Hide 捉迷藏 动态树分治
- hibernate配置详情1(hibernate.cfg.xml)
- javaweb项目的分包笔记
- 根据二叉树的中序和后序遍历,求前序遍历
- 蓝桥杯-排序-冒泡排序
- hibernate配置详情2(Dept.hbm.xml)
- 动态点分治:bzoj 3730,bzoj 1095
- spring四种依赖注入方式
- 什么是https
- B树,B+树,B-树
- hibernate配置详情3(Dept)
- Bmob在android studio中的环境配置和初始化
- HDU - 2085 - 核反应堆
- Mining and summarizing customer reviews论文总结
- 2017-2-17get