zoukankan      html  css  js  c++  java
  • 【BZOJ4538】[HNOI2016] 网络(整体二分+树状数组)

    点此看题面

    大致题意: 给定一棵无根树,三种操作:建立一个权值(x)的经过两点树上路径的任务;取消之前的一个任务;询问所有不经过树上给定点的任务中最大的权值。

    整体二分

    看到这道题,我们首先应该想到整体二分。(实际上我这种奇葩首先想到的是树套树

    考虑以答案为区间二分,每次把权值小于等于(mid)的任务扔到左区间,权值大于(mid)的任务在树上修改并扔到右区间。

    接下来对于一个询问,我们只要判断此时若存在不经过该点的任务,这个询问的答案就大于(mid),否则就小于等于(mid)

    然后就是如何有效维护信息以及修改的问题了。

    树上差分

    二分之后的每次修改相当于给一条树上路径加/减(1)

    树上路径?我会树剖!

    然而,其实这种题目只要树上差分一下就可以了。

    考虑对((x,y))间的路径加上(1),只要给(x,y)分别加(1),然后给(LCA(x,y))(1)(fa_{LCA(x,y)})(1),则一个点的点权就相当于是它子树内的点权和。

    众所周知,子树在(dfs)序列上是一段区间。

    于是就变成了单点修改、区间查询,显然一个树状数组就好了。

    具体实现详见代码。

    代码

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 100000
    #define M 200000
    #define LN 20
    #define add(x,y) (e[++ee].nxt=lnk[x],e[lnk[x]=ee].to=y)
    #define swap(x,y) (x^=y^=x^=y)
    using namespace std;
    int n,m,dc,dv[M+5],d,dI[N+5],dO[N+5],dep[N+5],fa[N+5][LN+5];
    int ee,lnk[N+5];struct edge {int to,nxt;}e[N<<1];
    struct Op {int op,x,y,v;}q[M+5],sl[M+5],sr[M+5];int ans[M+5];
    class FastIO
    {
    	private:
    		#define FS 100000
    		#define tc() (A==B&&(B=(A=FI)+fread(FI,1,FS,stdin),A==B)?EOF:*A++)
    		#define pc(c) (C==E&&(clear(),0),*C++=c)
    		#define D isdigit(c=tc())
    		int T;char c,*A,*B,*C,*E,FI[FS],FO[FS],S[FS];
    	public:
    		I FastIO() {A=B=FI,C=FO,E=FO+FS;}
    		Tp I void read(Ty& x) {x=0;W(!D);W(x=(x<<3)+(x<<1)+(c&15),D);}
    		Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
    		Tp I void writeln(Ty x) {W(S[++T]=x%10+48,x/=10);W(T) pc(S[T--]);pc('
    ');}
    		I void writeNA() {pc('-'),pc('1'),pc('
    ');}
    		I void clear() {fwrite(FO,1,C-FO,stdout),C=FO;}
    }F;
    I void dfs(CI x)//dfs初始化
    {
    	RI i;for(dI[x]=++d,i=1;i<=LN;++i) fa[x][i]=fa[fa[x][i-1]][i-1];
    	for(i=lnk[x];i;i=e[i].nxt) fa[x][0]^e[i].to&&
    		(dep[e[i].to]=dep[fa[e[i].to][0]=x]+1,dfs(e[i].to),0);dO[x]=d;
    }
    I int LCA(RI x,RI y)//倍增LCA
    {
    	RI i;dep[x]<dep[y]&&swap(x,y);
    	for(i=0;dep[x]^dep[y];++i) (dep[x]^dep[y])>>i&1&&(x=fa[x][i]);if(x==y) return x;
    	for(i=LN;~i;--i) fa[x][i]^fa[y][i]&&(x=fa[x][i],y=fa[y][i]);return fa[x][0];
    }
    class TreeArray//树状数组
    {
    	private:
    		int a[M+5];
    	public:
    		I void U(RI x,CI y) {W(x<=n) a[x]+=y,x+=x&-x;}//单点修改
    		I int Q(RI x,RI t=0) {W(x) t+=a[x],x-=x&-x;return t;}//询问前缀和(差分求出区间和)
    }T;int cnt;
    I void F5(CI id,CI op)//根据一个询问差分修改
    {
    	RI z=LCA(q[id].x,q[id].y),v=q[id].v<0?-op:op;cnt+=v;
    	T.U(dI[q[id].x],v),T.U(dI[q[id].y],v),T.U(dI[z],-v),z^1&&(T.U(dI[fa[z][0]],-v),0);
    }
    I void Solve(CI l,CI r,CI L,CI R)//整体二分
    {
    	RI i;if(l==r) {for(i=L;i<=R;++i) q[i].op&&(ans[q[i].v]=l);return;}//边界
    	RI mid=l+r>>1,tl=0,tr=0;for(i=L;i<=R;++i)
    	{
    		if(!q[i].op) {(abs(q[i].v)<=mid?sl[++tl]:(F5(i,1),sr[++tr]))=q[i];continue;}//对于任务
    		((T.Q(dO[q[i].x])-T.Q(dI[q[i].x]-1))^cnt?sr[++tr]:sl[++tl])=q[i];//对于询问
    	}
    	for(i=L;i<=R;++i) !q[i].op&&abs(q[i].v)>mid&&(F5(i,-1),0);//清空
    	for(i=1;i<=tl;++i) q[L+i-1]=sl[i];for(i=1;i<=tr;++i) q[L+tl-1+i]=sr[i];//把分到两边的询问放回原数组
    	Solve(l,mid,L,L+tl-1),Solve(mid+1,r,L+tl,R);//递归
    }
    int main()
    {
    	RI i,x,y;for(F.read(n,m),i=1;i^n;++i) F.read(x,y),add(x,y),add(y,x);dfs(1);
    	for(i=1;i<=m;++i) F.read(q[i].op,q[i].x),!q[i].op&&(F.read(q[i].y,q[i].v),dv[++dc]=q[i].v);
    	RI t=0;for(sort(dv+1,dv+dc+1),dc=unique(dv+1,dv+dc+1)-dv-1,i=1;i<=m;++i) switch(q[i].op)
    	{
    		case 0:q[i].v=lower_bound(dv+1,dv+dc+1,q[i].v)-dv;break;//离散化
    		case 1:q[i]=q[q[i].x],q[i].v*=-1;break;case 2:q[i].v=++t;break;//v<0表示删除
    	}Solve(0,dc,1,m);
    	for(i=1;i<=t;++i) ans[i]?F.writeln(dv[ans[i]]):F.writeNA();return F.clear(),0;//输出答案
    }
    
  • 相关阅读:
    房价
    Jsrender初体验
    GCD XOR UVA
    GCD
    Aladdin and the Flying Carpet LightOJ
    HDU6035 2017多校第一场1003 树形DP
    F
    C
    B
    An Easy Physics Problem HDU
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/BZOJ4538.html
Copyright © 2011-2022 走看看