• Luogu-3250 [HNOI2016]网络


    Luogu-3250 [HNOI2016]网络

    题面

    Luogu-3250

    题解

    CDQ分治...这个应该算是整体二分吧

    二分重要度,按照时间从小到大加入大于重要度的边

    对于一个询问,如果经过这个点的边数不等于加入的边数,那就说明有比重要度大而且不经过这个点的边,然后分成两部分继续做

    看Candy?大佬的博客学会了一种加边方法:记录dfn序,对于一条边(u)(v)。让端点的(cnt)++,(lca)(fa[lca])的--,找经过一个点边数只需要查询他的子树大小就好啦

    代码

    #include<map>
    #include<queue>
    #include<cmath>
    #include<ctime>
    #include<stack>
    #include<bitset>
    #include<vector>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    inline char gc(){
    //static char buf[100000],*p1,*p2;
    //return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
        return getchar();
    }
    inline int read(){
        int ans=0,fh=1;
        char ch=gc();
        while(ch<'0'||ch>'9'){if(ch=='-') fh=-1; ch=gc();}
        while(ch>='0'&&ch<='9')	ans=(ans<<1)+(ans<<3)+ch-'0',ch=gc();
        return ans*fh;
    }
    const int maxn=2e5+100,maxm=maxn<<1;
    struct node{
        int a,b,v;
    }c[maxn];
    int n,m,head[maxn],nex[maxm],v[maxm],num=1;
    int tre[maxn],cr[maxn],cl;
    int fa[maxn],top[maxn],siz[maxn],dep[maxn],son[maxn],dfn[maxn],tim;
    int tmp1[maxn],tmp2[maxn],p[maxn],ans[maxn],mx,qtot;
    void revise(int x,int z){
        for(int i=x;i<maxn;i+=i&(-i))
            if(cr[i]==cl) tre[i]+=z;
            else cr[i]=cl,tre[i]=z;
    }
    int query(int x,int Ans=0){
        for(int i=x;i;i-=i&(-i))
            if(cr[i]==cl) Ans+=tre[i];
        return Ans;
    }
    void add(int x,int y){
        v[++num]=y;
        nex[num]=head[x];
        head[x]=num;
        v[++num]=x;
        nex[num]=head[y];
        head[y]=num;
    }
    void dfs1(int x,int f,int dp){
        fa[x]=f,dep[x]=dp,siz[x]=1;
        for(int i=head[x];i;i=nex[i]){
            int y=v[i];
            if(y==f) continue;
            dfs1(y,x,dp+1);
            if(siz[y]>siz[son[x]])
                son[x]=y;
            siz[x]+=siz[y];
        }
    }
    void dfs2(int x,int tp){
        top[x]=tp,dfn[x]=++tim;
        if(son[x]) dfs2(son[x],tp);
        for(int i=head[x];i;i=nex[i])
            if(v[i]!=fa[x]&&v[i]!=son[x])
                dfs2(v[i],v[i]);
    }
    int Lca(int x,int y){
        while(top[x]!=top[y]){
            if(dep[top[x]]<dep[top[y]]) swap(x,y);
            x=fa[top[x]];
        }
        return dep[x]<dep[y]?x:y;
    }
    void work(int x,int y,int z){
        int lca=Lca(x,y);
        revise(dfn[x],z),revise(dfn[y],z);
        revise(dfn[lca],-z);if(lca!=1) revise(dfn[fa[lca]],-z);
    }
    int check(int x){
        int l=dfn[x],r=dfn[x]+siz[x]-1;
        return query(r)-query(l-1);
    }
    void cdq(int l,int r,int L,int R){
        if(L>R) return;
        if(l==r){
            int ltot=0;cl++;
            for(int i=L;i<=R;i++){
                int x=p[i],z=c[x].v>0?1:-1;
                if(~c[x].b) work(c[x].a,c[x].b,z),ltot+=z;
                else if(check(c[x].a)!=ltot) ans[c[x].v]=l;
            }
            return;
        }
        int mid=l+r>>1;
        int lc=0,rc=0,cnt=L-1,ltot=0;cl++;
        for(int i=L;i<=R;i++){
            int x=p[i],z=c[x].v>0?1:-1;
            if(~c[x].b){
                if(abs(c[x].v)>mid)
                    work(c[x].a,c[x].b,z),tmp2[++rc]=x,ltot+=z;
                else tmp1[++lc]=x;
            }
            else{
                int pp=check(c[x].a);
                if(pp!=ltot) tmp2[++rc]=x;
                else tmp1[++lc]=x;
            }
        }
        for(int i=1;i<=lc;i++) p[++cnt]=tmp1[i];
        for(int i=1;i<=rc;i++) p[++cnt]=tmp2[i];
        cdq(l,mid,L,L+lc-1),cdq(mid+1,r,L+lc,R);
    }
    int main(){
    //	freopen("3250.in","r",stdin);
        n=read(),m=read();
        int x,y,ms,z;
        for(int i=1;i<n;i++)
            x=read(),y=read(),add(x,y);
        dfs1(1,1,1);
        dfs2(1,1);
        for(int i=1;i<=m;i++){
            ms=read(),p[i]=i;
            if(!ms){
                x=read(),y=read(),z=read();
                c[i]=(node){x,y,z},mx=max(mx,z);
            }
            else{
                x=read();
                if(ms==1) c[i]=c[x],c[i].v*=-1;
                else c[i].a=x,c[i].b=-1,c[i].v=++qtot;
            }
        }
        memset(ans,-1,sizeof(ans));
        cdq(1,mx,1,m);
        for(int i=1;i<=qtot;i++)
            printf("%d
    ",ans[i]);
        return 0;
    }
    
  • 相关阅读:
    软件错误,软件缺陷,软件故障与软件失效
    QEMU命令创建KVM Guest(bridge桥接)
    Linux下设置网卡随系统启动
    RHEL查看CPU等机器信息
    QEMU/KVM功能测试
    CentOS 删除自带的OpenJDK 和 安装SunJDK
    将Centos的yum源更换为国内的阿里云源
    Centos6.8下安装oracle_11gr2版主要过程
    Centos6.8下安装oracle_11gr2版主要过程
    opendrive.com提供的免费网盘
  • 原文地址:https://www.cnblogs.com/nianheng/p/10181982.html
Copyright © 2020-2023  润新知