• [UOJ UNR#1]奇怪的线段树


    来自FallDream的博客,未经允许,请勿转载, 谢谢。


    原题可以到UOJ看,传送门

    如果存在一个点是白的,却有儿子是黑的,显然无解。

    不然的话,只要所有黑色的“黑叶子”节点,即没有黑色的儿子的节点有访问到就行了。

    联想到今年CTSC上一道题叫“被操纵的线段树”,每个点被访问之后,可以和他合并的点满足左端点是它的右端点+1,并且和它没有相同的父亲。

    发现这些点构成一条链,所以只需要向最大的那个点连边就行了,然后每个点向左儿子连边。

    拆点之后,给所有的“黑色叶子”节点中间的边加上流量下界,求出最小流就是答案了。

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<cstdio>
    #include<vector>
    #define S 0
    #define T 16001
    #define SS 16002
    #define TT 16003
    #define MN 16003
    #define INF 2000000000
    using namespace std;
    inline int read()
    {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    int n,q[MN+5],c[MN+5],d[MN+5],head[MN+5],cnt=1,Lt[MN+5],Rt[MN+5],dn=0,m;
    int in[MN+5],L[MN+5],R[MN+5],s[MN+5],ss[MN+5],fa[MN+5],top;
    struct edge{int to,next,w;}e[MN*100+5];
    vector<int> v[MN+5];
    
    inline void ins(int f,int t,int w)
    {
        e[++cnt]=(edge){t,head[f],w};head[f]=cnt;
        e[++cnt]=(edge){f,head[t],0};head[t]=cnt;    
    }
    
    int Build(int l,int r)
    {
        int x=++dn;s[x]=read();Lt[x]=l;Rt[x]=r;v[l].push_back(x);
        if(l!=r) 
        {
            int mid=read();
            fa[L[x]=Build(l,mid)]=x;
            fa[R[x]=Build(mid+1,r)]=x;
            ss[x]|=ss[L[x]]|ss[R[x]];
            if(!s[x]&&ss[x]){puts("OwO");exit(0);}
            ins(x,L[x],INF);
        }
        if(ss[x]|s[x]) ins(x,x+m,INF);
        if(s[x]&&!ss[x]) ins(S,x,INF),--in[x],++in[x+m],ins(x+m,T,INF);
        ss[x]|=s[x];return x;
    }
    
    bool bfs()
    {
        memset(d,0,sizeof(d));int i,j;
        for(d[q[top=i=1]=SS]=1;i<=top;++i)
            for(j=c[q[i]]=head[q[i]];j;j=e[j].next)
                if(e[j].w&&!d[e[j].to]) d[q[++top]=e[j].to]=d[q[i]]+1;
        return d[TT];    
    }
    
    int dfs(int x,int f)
    {
        if(x==TT) return f;int used=0;
        for(int&i=c[x];i;i=e[i].next)
            if(e[i].w&&d[e[i].to]==d[x]+1)
            {
                int w=dfs(e[i].to,min(f-used,e[i].w));
                used+=w;e[i].w-=w;e[i^1].w+=w;
                if(used==f) return f;
            }
        return d[x]=-1,used;
    }
    
    int main()
    {
        n=read();m=2*n-1;Build(1,n);
        for(int i=1,j,k;i<=dn;++i)
            for(j=0,k=Rt[i]+1;j<v[k].size();++j)
                if(v[k][j]!=R[fa[i]]) {ins(i+m,v[k][j],INF);break;}
        for(int i=1;i<=dn<<1;++i) if(in[i]>0) ins(SS,i,in[i]); else if(in[i]<0) ins(i,TT,-in[i]);
        while(bfs()) dfs(SS,INF);ins(T,S,INF);
        while(bfs()) dfs(SS,INF);
        printf("%d
    ",e[cnt].w);
        return 0;
    }
  • 相关阅读:
    axb_2019_fmt32 盲打和格式化字符串
    ciscn_2019_final_3 需要避开当前free的chunk的下一个chunk不能超过arena的边界
    xdctf2015_pwn200
    valarray类
    Mysql 常用命令.
    如何处理IO
    等号两边自动添加括号
    Request JSON
    开机小脚本自动打开sublime text 和git-bash
    git 同步勾子
  • 原文地址:https://www.cnblogs.com/FallDream/p/uoj217.html
Copyright © 2020-2023  润新知