bzoj 4538: [Hnoi2016]网络 (整体二分+树状数组)
2017-06-27 20:08
399 查看
题目描述
传送门
题解
这道题比较好想的思路是树链剖分+线段树套堆。加入一条路径,其实就是用它的权值更新所有不是路径上的点,因为一条路径最多对应dfs序中的logn个区间,那么剩下的区间也是logn级别的,所以可以利用线段树的区间修改。
因为还有删除最大值的操作,所以我们对于线段树的每个区间开一个大根堆记录区间中所有的值。区间修改可持久化一下,这样每次最多加入logn个值,所有空间是mlogn的.
还有一个思路是整体二分+树状数组。按理来说这种方法应该会比上面的方法快,但是实际上非常的慢。
二分答案mid,将所有值大于mid的路径加入,然后判断经过某个点的路径数是否等于加入的路径数,如果等于就将操作分到[l,mid].
设加入的路径为x->y,pos[x]++,pos[y]++,pos[lca]–,pos[fa[lca]]–.
统计经过一个点的路径个数的时候之需要查询子树的答案即可。
代码
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #define N 200003 using namespace std; struct data{ int x,id,opt,k; }q ,p ; int tr ,tot,point ,v ,nxt ,deep ,mi[20],l ,r ; int fa [20],sz,pos ,n,m,ans ,a ,b ,c ; void add(int x,int y) { tot++; nxt[tot]=point[x]; point[x]=tot; v[tot]=y; tot++; nxt[tot]=point[y]; point[y]=tot; v[tot]=x; } void dfs(int x,int f) { deep[x]=deep[f]+1; l[x]=++sz; for (int i=1;i<=17;i++){ if (deep[x]-mi[i]<0) break; fa[x][i]=fa[fa[x][i-1]][i-1]; } for (int i=point[x];i;i=nxt[i]) { if (v[i]==f) continue; fa[v[i]][0]=x; dfs(v[i],x); } r[x]=sz; } int lca(int x,int y) { if (deep[x]<deep[y]) swap(x,y); int k=deep[x]-deep[y]; for (int i=0;i<=17;i++) if ((k>>i)&1) x=fa[x][i]; if (x==y) return x; for (int i=17;i>=0;i--) if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i]; return fa[x][0]; } int lowbit(int x){ return x&(-x); } void pointchange(int x,int v) { for (int i=x;i<=n;i+=lowbit(i)) tr[i]+=v; } int query(int x) { int ans=0; if (x==0) return ans; for (int i=x;i>=1;i-=lowbit(i)) ans+=tr[i]; return ans; } void change(int x,int y,int v) { pointchange(l[x],v); pointchange(l[y],v); int t=lca(x,y); pointchange(l[t],-v); if (t!=1) pointchange(l[fa[t][0]],-v); } void solve(int L,int R,int ls,int rs) { if (ls>rs) return; if (L==R) { int cnt=0; for (int i=ls;i<=rs;i++) if (q[i].opt==1) ans[q[i].k]=L; return; } int mid=(L+R)>>1; int cntx=ls-1; int cnty=0; int cnt=0; for (int i=ls;i<=rs;i++) { if (q[i].opt==0) { if (c[q[i].x]>mid){ cnt+=q[i].k; change(a[q[i].x],b[q[i].x],q[i].k); p[++cnty]=q[i]; } else q[++cntx]=q[i]; } if (q[i].opt==1) { int t=query(r[q[i].x])-query(l[q[i].x]-1); if (t==cnt) q[++cntx]=q[i]; else p[++cnty]=q[i]; } } for (int i=1;i<=cnty;i++) q[cntx+i]=p[i]; for (int i=1;i<=cnty;i++) if (p[i].opt==0) change(a[p[i].x],b[p[i].x],-p[i].k); solve(L,mid,ls,cntx); solve(mid+1,R,cntx+1,rs); } int read(){ int ttt=0; char ch=0; while(ch<'0'||ch>'9')ch=getchar(); while(ch>='0'&&ch<='9')ttt=ttt*10+ch-'0',ch=getchar(); return ttt; } int main() { freopen("a.in","r",stdin); scanf("%d%d",&n,&m); for (int i=1;i<n;i++) { int x,y; x=read(); y=read(); add(x,y); } mi[0]=1; for (int i=1;i<=19;i++) mi[i]=mi[i-1]*2; dfs(1,0); int mx=1; int cnt=0; int tt=0; for (int i=1;i<=m;i++) { q[i].opt=read(); q[i].id=i; if (q[i].opt==0) a[i]=read(),b[i]=read(),c[i]=read(),mx=max(mx,c[i]),q[i].k=1,q[i].x=i; if (q[i].opt==1) { q[i].x=read(); q[i].opt=0; q[i].k=-1; } if (q[i].opt==2) q[i].x=read(),q[i].opt=1,q[i].k=++tt; } solve(-1,mx,1,m); for (int i=1;i<=tt;i++) printf("%d\n",ans[i]); }
相关文章推荐
- BZOJ 4538: [Hnoi2016]网络 [整体二分]
- Bzoj4538:[Hnoi2016]网络:整体二分+树状数组
- 4538: [Hnoi2016]网络 链剖 + 堆(优先队列) / 整体二分
- 【BZOJ4538】[Hnoi2016]网络 整体二分+树状数组
- bzoj 4538: [Hnoi2016]网络
- 【BZOJ4009】[HNOI2015]接水果 DFS序+整体二分+扫描线+树状数组
- 【BZOJ 4538】【HNOI 2016】网络
- BZOJ4538:[Hnoi2016]网络 (整体二分+Lca+树状数组/线段树+路径交/树链剖分+Heap)
- BZOJ 4538|HNOI 2016|网络|树链剖分
- bzoj 4538: [Hnoi2016]网络 树链剖分+线段树
- 【BZOJ 4538】[Hnoi2016]网络 树链剖分+堆
- bzoj 4538: [Hnoi2016]网络
- BZOJ 4538: [Hnoi2016]网络
- bzoj 4538: [Hnoi2016]网络 树链剖分
- bzoj 4538: [Hnoi2016]网络
- BZOJ 4538 [Hnoi2016]网络
- 【bzoj4009】[HNOI2015]接水果 DFS序+树上倍增+整体二分+树状数组
- bzoj 4538: [Hnoi2016]网络
- [树链剖分 线段树 堆] BZOJ 4538 [Hnoi2016]网络
- BZOJ 4538: [Hnoi2016]网络