bzoj4538: [Hnoi2016]网络
2017-04-21 14:36
253 查看
传送门
本来想用树剖艹,然而并不会卡常数这种神奇的技能,,,于是还是乖乖写正解吧QAQ
我们可以把一个询问转化为二分判定性问题
二分答案K
,若所有权值大于K的路径都经过询问点x,则答案比K小,否则答案比K大
对于多组询问,外层再套一个整体二分就行了
至于判断有几条路径经过点x
,对于一条路径(u,v)我们把u和v置为1,lca(u,v)和lca(u,v)的父亲置为−1,这样经过一个节点x
的路径条数就是以其为根的子树的标记和,,,
由于子树区间求和有关,于是可以用dfs序维护
然后可以O(1)
求lca,即通过欧拉回路把lca转化为rmq问题。
本来想用树剖艹,然而并不会卡常数这种神奇的技能,,,于是还是乖乖写正解吧QAQ
我们可以把一个询问转化为二分判定性问题
二分答案K
,若所有权值大于K的路径都经过询问点x,则答案比K小,否则答案比K大
对于多组询问,外层再套一个整体二分就行了
至于判断有几条路径经过点x
,对于一条路径(u,v)我们把u和v置为1,lca(u,v)和lca(u,v)的父亲置为−1,这样经过一个节点x
的路径条数就是以其为根的子树的标记和,,,
由于子树区间求和有关,于是可以用dfs序维护
然后可以O(1)
求lca,即通过欧拉回路把lca转化为rmq问题。
#include<cmath> #include<cstdio> #include<cstring> #include<cstdlib> #include<iostream> #include<algorithm> #define fi first #define se second #define N 100005 using namespace std; pair<int,int> pos ; struct data{int op,id,x,ans;}q[N*2],tmp[N*2]; struct edge{int to,next;}e[N*2]; int head ,st[N*4][20],log_2[N*2],vis ; int dep ,A[N*2],B[N*2],C[N*2],bit ,fa ; int tot,ss,n,m,x,y,tim,mx; bool cmp(data x,data y){ return x.id<y.id; } void add(int x,int y){ e[++tot]=(edge){y,head[x]}; head[x]=tot; e[++tot]=(edge){x,head[y]}; head[y]=tot; } void dfs(int x){ pos[x].fi=++tim; st[++ss][0]=x; vis[x]=ss; for (int i=head[x];i;i=e[i].next) if (!vis[e[i].to]){ fa[e[i].to]=x; dep[e[i].to]=dep[x]+1; dfs(e[i].to); st[++ss][0]=x; } pos[x].se=tim; } int Min(int x,int y){ return dep[x]<dep[y]?x:y; } void build(){ for (int i=2;i<=ss;i++) log_2[i]=log_2[i>>1]+1; for (int j=1;j<=log_2[ss];j++) for (int i=1;i<=ss;i++) st[i][j]=Min(st[i][j-1],st[i+(1<<(j-1))][j-1]); } int lca(int x,int y){ x=vis[x]; y=vis[y]; if (x>y) swap(x,y); int len=log_2[y-x+1]; return Min(st[x][len],st[y-(1<<len)+1][len]); } void change(int x,int v){ for (;x<=n;x+=x&(-x)) bit[x]+=v; } int ask(int x){ int s=0; for (;x;x-=x&(-x)) s+=bit[x]; return s; } void update(int x,int y,int op){ int _lca=lca(x,y); change(pos[x].fi,op); change(pos[y].fi,op); change(pos[_lca].fi,-op); if (fa[_lca]) change(pos[fa[_lca]].fi,-op); } int query(int x){ return ask(pos[x].se)-ask(pos[x].fi-1); } void erfen(int L,int R,int l,int r){ if (L>R) return; int mid=(l+r)>>1; if (l==r){ for (int i=L;i<=R;i++) if (q[i].op==2) q[i].ans=mid; return; } int qq=L-1,tt=0,num=0; for (int i=L;i<=R;i++) if (q[i].op==2){ if (query(q[i].x)==num) q[++qq]=q[i]; else tmp[++tt]=q[i]; } else{ int op=q[i].op?-1:1; if (C[q[i].x]<=mid) q[++qq]=q[i]; else{ tmp[++tt]=q[i]; num+=op; update(A[q[i].x],B[q[i].x],op); } } for (int i=1;i<=tt;i++) if (tmp[i].op!=2){ int op=tmp[i].op?1:-1; update(A[tmp[i].x],B[tmp[i].x],op); } for (int i=1;i<=tt;i++) q[qq+i]=tmp[i]; erfen(L,qq,l,mid); erfen(qq+1,qq+tt,mid+1,r); } int main(){ //freopen("1.in","r",stdin); scanf("%d%d",&n,&m); for (int i=1;i<n;++i){ scanf("%d%d",&x,&y); add(x,y); } dfs(1); build(); for (int i=1;i<=m;i++){ scanf("%d",&q[i].op); q[i].id=i; if (q[i].op==0){ scanf("%d%d%d",&A[i],&B[i],&C[i]); q[i].x=i; mx=max(mx,C[i]); } else scanf("%d",&q[i].x); } erfen(1,m,-1,mx); sort(q+1,q+m+1,cmp); for (int i=1;i<=m;i++) if (q[i].op==2) printf("%d\n",q[i].ans); }
相关文章推荐
- bzoj4538 [Hnoi2016]网络
- 【BZOJ4538】【HNOI2016】网络
- BZOJ4538 : [Hnoi2016]网络
- [BZOJ4538][HNOI2016]网络-线段树-树链剖分
- 【bzoj4538】【HNOI2016】【网络】【树链剖分+线段树套堆】
- bzoj4538: [HNOI2016]网络
- 【BZOJ4538】【HNOI2016】网络
- bzoj4538 [Hnoi2016]网络
- bzoj4538: [Hnoi2016]网络
- bzoj4538 [Hnoi2016]网络
- 【bzoj4538】[Hnoi2016]网络
- BZOJ4538: [Hnoi2016]网络
- BZOJ4538:[Hnoi2016]网络 (整体二分+Lca+树状数组/线段树+路径交/树链剖分+Heap)
- bzoj4538: [Hnoi2016]网络
- bzoj4538: [Hnoi2016]网络
- bzoj4538 [Hnoi2016]网络
- Bzoj4538:[Hnoi2016]网络:整体二分+树状数组
- [bzoj4538][Hnoi2016]网络
- bzoj4538 [Hnoi2016]网络(树链剖分,线段树套堆)
- 【BZOJ4538】[Hnoi2016]网络 整体二分+树状数组