• [3.19FJ四校联考]


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

    ----------------------------------------------------

    A.积分,不会  以后补

    B.给定一个n*m的矩阵,每个点是0或者1,然后q个操作,每次把一个位置取反,然后询问最大的全是1的正方形的边长。n*m<=4000000 , q<=3900

    题解:我们用一个线段树把所有行维护起来,然后每一行对每一列维护这个行区间的这一列的u和d,u表示从最下面一个最多有多少个连续的1,d表示从上面网下面最多有多少个连续的1,这两个参数是很好合并的。然后我们考虑计算过中线的答案。我们用两个指针ij,再用两个单调队列,维护u和d单调下降。每当 i - j + 1> u[tail] + d[tail] 的时候,我们把j指针往前移。最后我们用i - j + 1更新答案。

    复杂度qmlogn  如果n<m我们把nm交换一下。

    最近被奇怪的代码风格洗脑了,写了一个不像是我写的程序(听我解释,我真的不是抄的.....) 其实我真正的代码风格像C题那样就是一团垃圾

    #include<iostream>
    #include<cstdio>
    #define MN 2000
    #define TEST
    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;
    }
    
    inline int cread()
    {
        char ch = getchar();
        while(ch != '.' && ch != 'X') ch = getchar();
        return ch == '.' ? 1 : 0;
    }
    
    int n , m , q , qx[MN + 5] , ltop , qy[MN + 5] , rtop , ltail , rtail;
    bool *s[MN + 5] , rev;
    
    struct Segment_Tree{
        int ans , w;
        int *u , *d;
        Segment_Tree *l , *r;
        void init(int x)
        {
            ans = 0;
            for(int i = 1 ; i <= n ; ++i)
                u[i] = d[i] = s[i][x] , ans |= s[i][x]; 
        }
        
        void update()
        {
            ans = max ( l->ans , r->ans );
            
            int x , k = 1;
            for(int i = 1 ; i <= n ; ++i)
            {
                u[i] = l -> d[i];    
                d[i] = r -> u[i]; 
            }        
                            
            qx[ltop = 1] = qy[rtop = 1] = 1;
            ltail = rtail = 1;
            
            for ( int i = 2; i <= n ; ++i)
            {
                while(u[i] <= u[qx[ltop]] && ltop >= ltail) ltop --;
                while(d[i] <= d[qy[rtop]] && rtop >= rtail) rtop --;
                
                qx[++ ltop] = i; 
                qy[++ rtop] = i; 
    
                while(i - k + 1> u[qx[ltail]] + d[qy[rtail]] && i > k) 
                {
                    ++ k;
                    if(qx[ltail] < k) ltail ++; 
                    if(qy[rtail] < k) rtail ++;
                }
                ans = max(ans , i - k + 1);
            }
            
            for(int i = 1 ; i <= n ; ++i)
            {
                u[i] = ( l -> u[i] == l -> w) ? r -> u[i] + l -> w : l -> u[i];    
                d[i] = ( r -> d[i] == r -> w) ? l -> d[i] + r -> w : r -> d[i]; 
            }    
        }
        
        void modify(int x , int lt = 1 , int rt = m)
        {
            if(lt == rt) { init(x); return;}
            int mid = lt + rt >> 1;
            if(x <= mid) l -> modify(x , lt , mid);
            else  r -> modify(x , mid + 1, rt);
            update();
        }
        
        Segment_Tree(int  lt , int rt )
        {
            u = new int [n + 2];
            d = new int [n + 2];
            w = rt - lt + 1;
            if(lt == rt) { init(lt); return;}
            int mid = lt + rt >> 1;
            l = new Segment_Tree(lt , mid);
            r = new Segment_Tree(mid + 1 , rt);
            update(); 
        }
        
    }*rt;
    
    int main()
    {
    #ifdef TEST
        freopen("s.in" , "r" , stdin);
        freopen("s.out" , "w" , stdout);
    #endif
    
        n = read(); m = read(); q = read();
        if( n > m) swap(n , m),rev = true; 
        for(int i = 1; i <= n ; ++i)
            s[i] = new bool [m + 2]; 
        
        if(!rev)
            for(int i = 1; i <= n ; ++i)
                for(int j = 1; j <= m ; ++j)
                    s[i][j] = cread();
        else 
            for(int i = 1; i <= m ; ++i)
                for(int j = 1; j<= n ; ++j)
                    s[j][i] = cread();
                    
        rt = new Segment_Tree(1 , m);
    
        for(int i = 1; i <= q ; ++i)
        {
            int x = read() , y = read();
            if(rev) swap(x , y);
            s[x][y] ^= 1;
            rt -> modify(y);
            printf("%d
    " , rt -> ans);
        }        
        return 0;
    }

    C.给定一棵n个点树,每个点可以涂成白的或者黑的。给定b条链和b个权值bi,表示这条链上的点全是黑色时候能得到bi的贡献。还有a条链和a个权值,表示全部涂成白色能得到的贡献。你要求出最大贡献。n<=100000  a,b<=30000  3s

    题解:神题

    最小割,很显然黑白链就是一个二分图。但是直接建图是不行的,所以我们考虑优化一下,把树拿去树剖一下,然后建两棵线段树,一棵只能往下走,一棵只能往上走。每条链对两棵线段树上的对应的log个区间建边,最后跑一次最小割。复杂度很玄学,就算O(能过)吧。

    ditoly真的强,居然在现场想出了这个做法...%%%

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    #define N 800000
    #define MAXL 10000000
    #define MV 860000
    #define MAXN 100000
    #define MN 100000
    #define S 0
    #define tt 860001
    #define INF 2000000000
    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 dn=0,cnt=0,ans=0,n,B,W,head2[MAXN+5],head[MV+5],top[MAXN+5],qx[MV+5],qtop,tail;
    int dfn[MAXN+5],mx[MAXN+5],size[MAXN+5],dep[MAXN+5],fa[MAXN+5],q[MV+5],tp[MV+5];
    struct edge{
        int to,next,w;
    }e[MAXL*2+5];
    struct edge2{
        int to,next;
    }e2[MAXN*2+5];
    struct TREE{
        int l,r;
    }T[MN*4+5];
    
    inline void ins(int f,int t){e2[++cnt].next=head2[f];head2[f]=cnt;e2[cnt].to=t;}
    inline void ins(int f,int t,int w){e[++cnt].next=head[f];head[f]=cnt;e[cnt].to=t;e[cnt].w=w;}
    inline void insw(int f,int t,int w){ins(f,t,w);ins(t,f,0);}
    
    void dfs(int x,int f)
    {
        size[x]=1;mx[x]=0;fa[x]=f;int maxn=0;
        for(int i=head2[x];i;i=e2[i].next)if(e2[i].to!=f)
        {
            dep[e2[i].to]=dep[x]+1;dfs(e2[i].to,x);
            size[x]+=size[e2[i].to];
            if(size[e2[i].to]>maxn){maxn=size[e2[i].to];mx[x]=e2[i].to;}
        }
    }
    
    void dfs2(int x,int t)
    {
        top[x]=t;dfn[x]=++dn;
        if(mx[x])dfs2(mx[x],t);
        for(int i=head2[x];i;i=e2[i].next)if(!dfn[e2[i].to])
        {dfs2(e2[i].to,e2[i].to);}
    }
    
    void build(int x,int l,int r)
    {
        T[x].l=l;T[x].r=r;if(l==r)return;
        int mid=(l+r)>>1;
        insw(x,x<<1,INF);insw(x,x<<1|1,INF);
        insw((x<<1)+4*MN,x+4*MN,INF);insw((x<<1|1)+4*MN,x+4*MN,INF);
        build(x<<1,l,mid);build(x<<1|1,mid+1,r);
    }
    
    void insert(int from,int x,int l,int r)
    {
     //   cout<<"insert"<<from<<" "<<x<<" "<<l<<" "<<r<<" "<<lt<<" "<<rt<<endl;
        if(T[x].l==l&&T[x].r==r){insw(from,x,INF);insw(from,x+MN*4,INF);return;}
        int mid=(T[x].l+T[x].r)>>1;
        if(r<=mid)insert(from,x<<1,l,r);
        else if(l>mid)insert(from,x<<1|1,l,r);
        else {insert(from,x<<1,l,mid);insert(from,x<<1|1,mid+1,r);}
    }
    
    void insert2(int to,int x,int l,int r)
    {
      //  cout<<"insert2"<<to<<" "<<x<<" "<<l<<" "<<r<<" "<<lt<<" "<<rt<<endl;
        if(T[x].l==l&&T[x].r==r){insw(x,to,INF);insw(x+MN*4,to,INF);return;}
        int mid=(T[x].l+T[x].r)>>1;
        if(r<=mid)insert2(to,x<<1,l,r);
        else if(l>mid)insert2(to,x<<1|1,l,r);
        else {insert2(to,x<<1,l,mid);insert2(to,x<<1|1,mid+1,r);}
    }
    
    bool bfs()
    {
        memset(q,0,sizeof(q));int i,j;
        for(q[qx[qtop=i=0]=S]=1;i<=qtop;i++)
            for(int j=tp[qx[i]]=head[qx[i]];j;j=e[j].next)if(!q[e[j].to]&&e[j].w)
            q[qx[++qtop]=e[j].to]=q[qx[i]]+1;
        return q[tt]>0;
    }
    
    int solve(int x,int f)
    {
       // cout<<"solve"<<x<<" "<<f<<endl;
        if(x==tt)return f;int used=0;
        for(int&i=tp[x];i;i=e[i].next)
        if(e[i].w&&q[e[i].to]==q[x]+1)
        {
            int w=solve(e[i].to,min(f-used,e[i].w));
            used+=w;e[i].w-=w;e[i^1].w+=w;
            if(e[i].w) tp[x]=i;
            if(used==f)return f;
        }
        if(!used)q[x]=-1;
        return used;
    }
    
    int main()
    {
        freopen("t.in","r",stdin);
          freopen("t.out","w",stdout);
        n=read();B=read();W=read();
        for(int i=1;i<n;i++)
        {int u=read(),v=read();ins(u,v),ins(v,u);}
        cnt=1;dfs(1,0);dfs2(1,1);
        build(1,1,n);
        for(int i=1;i<=B;++i)
        {
            int u=read(),v=read(),x=read();insw(S,N+i,x);ans+=x;
            while(top[u]!=top[v])
            {
              //  cout<<u<<" "<<v<<" "<<top[u]<<" "<<top[v]<<endl;
                if(dep[top[u]]>dep[top[v]])
                {insert(N+i,1,dfn[top[u]],dfn[u]);u=fa[top[u]];}
                else
                {insert(N+i,1,dfn[top[v]],dfn[v]);v=fa[top[v]];}
            }
            if(dfn[u]>dfn[v])swap(u,v);insert(N+i,1,dfn[u],dfn[v]);
        }
        for(int i=1;i<=W;++i)
        {
            int u=read(),v=read(),x=read();insw(N+i+B,tt,x);ans+=x;
            while(top[u]!=top[v])
            {
               // cout<<u<<" "<<v<<" "<<top[u]<<" "<<top[v]<<endl;
                if(dep[top[u]]>dep[top[v]])
                {insert2(N+i+B,1,dfn[top[u]],dfn[u]);u=fa[top[u]];}
                else
                {insert2(N+i+B,1,dfn[top[v]],dfn[v]);v=fa[top[v]];}
            }
            if(dfn[u]>dfn[v])swap(u,v);insert2(N+i+B,1,dfn[u],dfn[v]);
        }
        while(bfs())ans-=solve(S,INF);
        printf("%d
    ",ans);
        return 0;
    }
  • 相关阅读:
    Makefile:2:*** missing separator. Stop.
    Code笔记之:对使用zend加密后的php文件进行解密
    Apache 访问控制
    leetcode-21-合并两个有序链表
    tcp四次挥手的过程
    实现一个LRU算法
    redis为什么快
    二月春日
    你的支持会鼓励我更积极地创作
    静夜思·静夜祈愿
  • 原文地址:https://www.cnblogs.com/FallDream/p/liankao319.html
Copyright © 2020-2023  润新知