zoukankan      html  css  js  c++  java
  • 洛咕P3250 [HNOI2016]网络 整体二分

    这题太神仙了必须写博客。。。

    显然可以想到二分答案。二分一个答案mid,如果所有长度(geq mid)的路径都过x,那么答案一定(<mid),否则答案(geq mid)

    那么就可以写出代码了,树状数组套动态开点线段树即可。时间复杂度(O(n(log_2n)^3))

    然后因为出题人卡空间就炸了。。。如果256M就能过了。。

    #include<bits/stdc++.h>
    #define il inline
    #define vd void
    typedef long long ll;
    il int gi(){
        int x=0,f=1;
        char ch=getchar();
        while(!isdigit(ch)){
            if(ch=='-')f=-1;
            ch=getchar();
        }
        while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
        return x*f;
    }
    int n,m,fir[100010],nxt[200010],dis[200010],id;
    il vd link(int a,int b){
        nxt[++id]=fir[a],fir[a]=id,dis[id]=b;
        nxt[++id]=fir[b],fir[b]=id,dis[id]=a;
    }
    int dfn[100010],dep[100010],fa[100010],siz[100010],son[100010];
    il vd dfs(int x){
        siz[x]=1;
        for(int i=fir[x];i;i=nxt[i]){
            if(dep[dis[i]])continue;
            dep[dis[i]]=dep[x]+1;
            fa[dis[i]]=x;
            dfs(dis[i]);
            siz[x]+=siz[dis[i]];
            if(siz[son[x]]<=siz[dis[i]])son[x]=dis[i];
        }
    }
    int top[100010];
    il vd dfs2(int x,int tp){
        top[x]=tp;dfn[x]=++dfn[0];
        if(son[x])dfs2(son[x],tp);
        for(int i=fir[x];i;i=nxt[i])if(fa[x]!=dis[i]&&son[x]!=dis[i])dfs2(dis[i],dis[i]);
    }
    int o[200010],u[200010],v[200010],w[200010];
    int uni_w[200010],uni_w_tot;
    int cnt,rt[200010],ls[15000001],rs[15000001],lz[15000001];
    #define mid ((l+r)>>1)
    il vd _update(int&x,int l,int r,const int&L,const int&R,const int&d){
        if(!x)x=++cnt;
        if(L<=l&&r<=R){lz[x]+=d;return;}
        if(L<=mid)_update(ls[x],l,mid,L,R,d);
        if(mid<R)_update(rs[x],mid+1,r,L,R,d);
    }
    il int _query(int&x,int l,int r,const int&p){
        if(!x)return 0;
        if(l==r)return lz[x];
        if(p<=mid)return lz[x]+_query(ls[x],l,mid,p);
        else return lz[x]+_query(rs[x],mid+1,r,p);
    }
    #undef mid
    il vd Update(const int&p,const int&l,const int&r,const int&d){
        int x=p;
        while(x<=uni_w_tot)_update(rt[x],1,n,l,r,d),x+=x&-x;
    }
    il int Query(const int&p,const int&l){
        int x=p,ret=0;
        while(x)ret+=_query(rt[x],1,n,l),x-=x&-x;
        return ret;
    }
    int t[200010];
    il vd bit_update(int x,int d){while(x<=uni_w_tot)t[x]+=d,x+=x&-x;}
    il int bit_query(int x){int r=0;while(x)r+=t[x],x-=x&-x;return r;}
    int main(){
        n=gi(),m=gi();
        for(int i=1;i<n;++i)link(gi(),gi());
        int RT=rand()%n+1;
        dep[RT]=1,dfs(RT),dfs2(RT,RT);
        for(int i=1;i<=m;++i){
            o[i]=gi();
            if(o[i]==0)u[i]=gi(),v[i]=gi(),w[i]=gi(),uni_w[++uni_w_tot]=-w[i];
            else if(o[i]==1){
                int t=gi();
                u[i]=u[t],v[i]=v[t],w[i]=w[t];
            }else if(o[i]==2)u[i]=gi();
        }
        std::sort(uni_w+1,uni_w+uni_w_tot+1);uni_w_tot=std::unique(uni_w+1,uni_w+uni_w_tot+1)-uni_w-1;
        for(int i=1;i<=m;++i)if(o[i]!=2)w[i]=std::lower_bound(uni_w+1,uni_w+uni_w_tot+1,-w[i])-uni_w;
        for(int i=1;i<=uni_w_tot;++i)uni_w[i]=-uni_w[i];
        for(int i=1;i<=m;++i){
            if(o[i]^2){
                int x=u[i],y=v[i],d=o[i]==0?1:-1;
                while(top[x]!=top[y])
                    if(dep[top[x]]>dep[top[y]])Update(w[i],dfn[top[x]],dfn[x],d),x=fa[top[x]];
                    else Update(w[i],dfn[top[y]],dfn[y],d),y=fa[top[y]];
                if(dfn[x]>dfn[y])std::swap(x,y);
                Update(w[i],dfn[x],dfn[y],d);
                bit_update(w[i],d);
            }else{
                if(!bit_query(uni_w_tot)){puts("-1");continue;}
                int l=1,r=uni_w_tot+1,mid;
                while(l<r){
                    mid=((l+r)>>1);
                    if(Query(mid,dfn[u[i]])==bit_query(mid))l=mid+1;
                    else r=mid;
                }
                if(l<=uni_w_tot)printf("%d
    ",uni_w[l]);
                else puts("-1");
            }
        }
        return 0;
    }
    

    然后学了一发神仙整体二分

    大概就是说答案要用二分求,可以放在一起二分

    大概就是void solve(int l,int r,int L,int R),就是([L,R])的操作/询问,操作的权值都(in[l,r]),这里面的查询都已经确定了在([l,r])范围内。

    如果(l=r)直接更新答案就好了,否则要确定这里面所有查询的

    按时间顺序操作,如果当前是修改而且权值(geq mid),就加入/删除一条u-v的路径;如果是询问就所有的路径是否都经过当前点即可,就能知道这个询问的答案是否(geq mid)。具体实现可以简单树上差分。

    然后递归调用下去。

    然后代码为了卡常把(geq)改成了(leq),具体见代码。。

    #include<bits/stdc++.h>
    #define il inline
    #define vd void
    typedef long long ll;
    il int gi(){
        int x=0;
        char ch=getchar();
        while(!isdigit(ch))ch=getchar();
        while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
        return x;
    }
    int n,m,fir[100010],nxt[200010],dis[200010],id;
    il vd link(int a,int b){
        nxt[++id]=fir[a],fir[a]=id,dis[id]=b;
        nxt[++id]=fir[b],fir[b]=id,dis[id]=a;
    }
    int dfn[100010],dep[100010],fa[100010],siz[100010],son[100010];
    il vd dfs(int x){
        siz[x]=1;
        for(int i=fir[x];i;i=nxt[i]){
            if(dep[dis[i]])continue;
            dep[dis[i]]=dep[x]+1;
            fa[dis[i]]=x;
            dfs(dis[i]);
            siz[x]+=siz[dis[i]];
            if(siz[son[x]]<=siz[dis[i]])son[x]=dis[i];
        }
    }
    int top[100010];
    il vd dfs2(int x,int tp){
        top[x]=tp;dfn[x]=++dfn[0];
        if(son[x])dfs2(son[x],tp);
        for(int i=fir[x];i;i=nxt[i])if(fa[x]!=dis[i]&&son[x]!=dis[i])dfs2(dis[i],dis[i]);
    }
    struct ques{int o,u,v,w,i,lca;bool y;}s[200010],a[200010],b[200010];
    int uni_w[200010],uni_w_tot,ans[200010];
    int t[200010];
    il vd update(int x,int d){while(x<=n)t[x]+=d,x+=x&-x;}
    il int query(int x){int r=0;while(x)r+=t[x],x-=x&-x;return r;}
    il vd solve(int l,int r,int L,int R){
    	if(L>R)return;
    	for(int i=L;i<=R;++i)if(s[i].o==2)goto GG;
    	return;GG:;
    	if(l==r){for(int i=L;i<=R;++i)if(s[i].i)ans[s[i].i]=l;return;}
    	int mid=(l+r)>>1,tot=0,A=0,B=0;
    	for(int i=L;i<=R;++i)
    		if(s[i].o==2){
    			if(query(dfn[s[i].u]+siz[s[i].u]-1)-query(dfn[s[i].u]-1)==tot)b[++B]=s[i];
    			else a[++A]=s[i];
    		}else if(s[i].w<=mid){
    			int d=s[i].o?-1:1;
    			tot+=d;
    			update(dfn[s[i].u],d);update(dfn[s[i].v],d);
    			update(dfn[s[i].lca],-d);if(s[i].lca!=1)update(dfn[fa[s[i].lca]],-d);
    			a[++A]=s[i];
    		}else b[++B]=s[i];
    	memcpy(s+L,a+1,(sizeof(ques))*A);
    	memcpy(s+L+A,b+1,(sizeof(ques))*B);
    	for(int i=L;i<=R;++i)
    		if(s[i].o!=2&&s[i].w<=mid&&s[i].y){
    			int d=s[i].o?1:-1;
    			update(dfn[s[i].u],d);update(dfn[s[i].v],d);
    			update(dfn[s[i].lca],-d);if(s[i].lca!=1)update(dfn[fa[s[i].lca]],-d);
    		}
    	solve(l,mid,L,L+A-1),solve(mid+1,r,L+A,R);
    }
    int main(){
        n=gi(),m=gi();
        for(int i=1;i<n;++i)link(gi(),gi());
        dep[1]=1,dfs(1),dfs2(1,1);
        for(int i=1;i<=m;++i){
            s[i].o=gi();
            if(s[i].o==0){
    			s[i].u=gi(),s[i].v=gi(),s[i].w=gi(),uni_w[++uni_w_tot]=-s[i].w;s[i].y=1;
    			int x=s[i].u,y=s[i].v;
    			while(top[x]!=top[y]){
    				if(dep[top[x]]>dep[top[y]])x=fa[top[x]];
    				else y=fa[top[y]];
    			}
    			s[i].lca=(dep[x]<dep[y])?x:y;
            }else if(s[i].o==1){
    			int x=gi();
    			s[i]=s[x],s[i].o=1;
    			s[i].y=s[x].y=0;
    		}else s[i].u=gi(),s[i].i=++ans[0];
    	}
    	uni_w[++uni_w_tot]=1;
    	std::sort(uni_w+1,uni_w+uni_w_tot+1);uni_w_tot=std::unique(uni_w+1,uni_w+uni_w_tot+1)-uni_w-1;
    	for(int i=1;i<=m;++i)if(s[i].o!=2)s[i].w=std::lower_bound(uni_w+1,uni_w+uni_w_tot+1,-s[i].w)-uni_w;
    	for(int i=1;i<=uni_w_tot;++i)uni_w[i]=-uni_w[i];
    	solve(1,uni_w_tot,1,m);
    	for(int i=1;i<=ans[0];++i)printf("%d
    ",uni_w[ans[i]]);
    	return 0;
    }
    

    卡了一波常数就洛咕rk1,bzoj rk7了。。

    upd:又改了一波 bzojrk1了

  • 相关阅读:
    Exp9 Web安全基础
    Exp 8 Web基础 ——20175201张驰
    Exp7 网络欺诈防范 20175201张驰
    《知识付费平台》个人报告——20175201张驰
    20175201 EXP6 MSF基础应用
    Exp5 信息搜集与漏洞扫描——20175201张驰
    Exp4 恶意代码分析—20175201张驰
    20175201张驰exp3——免杀原理与实践
    #20175201张驰 网络对抗exp2——后门原理与实践
    20175201张驰 网络对抗exp1—PC平台逆向破解
  • 原文地址:https://www.cnblogs.com/xzz_233/p/9884562.html
Copyright © 2011-2022 走看看