• Codeforces Global Round 8


    $A$:

    nt题,不说了。

    #include<bits/stdc++.h>
    #define maxn 200005
    #define maxm 500005
    #define inf 0x7fffffff
    #define ll long long
    #define rint register ll
    #define debug(x) cerr<<#x<<": "<<x<<endl
    #define fgx cerr<<"--------------"<<endl
    #define dgx cerr<<"=============="<<endl
     
    using namespace std;
     
    inline ll read(){
        ll x=0,f=1; char c=getchar();
        for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
        for(;isdigit(c);c=getchar()) x=x*10+c-'0';
        return x*f;
    }
     
    int main(){
        ll T=read();
        while(T--){
            ll a=read(),b=read(),n=read(),ans=0;
            while(1){
                if(a<b) swap(a,b);
                if(a>n) break;
                b+=a,ans++;
            }
            printf("%lld
    ",ans);
        }
        return 0;
    }
    A

    $B$:

    nt题,不说了。

    #include<bits/stdc++.h>
    #define maxn 200005
    #define maxm 500005
    #define inf 0x7fffffff
    #define ll long long
    #define rint register ll
    #define debug(x) cerr<<#x<<": "<<x<<endl
    #define fgx cerr<<"--------------"<<endl
    #define dgx cerr<<"=============="<<endl
     
    using namespace std;
    ll siz[maxn];
    char alp[10]={'c','o','d','e','f','o','r','c','e','s'};
     
    inline ll read(){
        ll x=0,f=1; char c=getchar();
        for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
        for(;isdigit(c);c=getchar()) x=x*10+c-'0';
        return x*f;
    }
     
    inline ll power(ll a,ll b){
        ll ans=1;
        while(b){
            if(b&1) ans=ans*a;
            a=a*a,b>>=1;
        }
        return ans;
    }
     
    int main(){
        ll k=read(),n=1;
        if(k==1){printf("codeforces");return 0;}
        while(power(n,10)<k) n++;
        ll res=power(n-1,10);
        for(ll i=1;i<=10;i++) siz[i]=n-1;
        for(ll i=1;i<=10;i++){
            siz[i]++,res=res/(siz[i]-1)*siz[i];
            if(res>=k) break;
        }
        for(ll i=1;i<=10;i++)
            for(ll j=1;j<=siz[i];j++)
                printf("%c",alp[i-1]);
        printf("
    ");
        return 0;
    }
    B

    $C$:

    nt题,不说了。

    #include<bits/stdc++.h>
    #define maxn 200005
    #define maxm 500005
    #define inf 0x7fffffff
    #define ll long long
    #define rint register int
    #define debug(x) cerr<<#x<<": "<<x<<endl
    #define fgx cerr<<"--------------"<<endl
    #define dgx cerr<<"=============="<<endl
     
    using namespace std;
    int tot=0,nxt[8][2]={{0,0},{0,1},{0,2},{1,2},{2,2},{2,1},{2,0},{1,0}};
    struct node{int x,y;}res[maxn];
     
    inline int read(){
        int x=0,f=1; char c=getchar();
        for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
        for(;isdigit(c);c=getchar()) x=x*10+c-'0';
        return x*f;
    }
     
    inline void ins(node a){
        for(int i=1;i<8;i++) 
            res[++tot]=(node){a.x+nxt[i][0],a.y+nxt[i][1]};
    }
     
    int main(){
        int n=read(); 
        node np=(node){0,0}; res[++tot]=np;
        ins(np),np=(node){np.x+2,np.y+2};
        for(int i=1;i<=n;i++)
            ins(np),np=(node){np.x+2,np.y+2};
        printf("%d
    ",tot);
        for(int i=1;i<=tot;i++) printf("%d %d
    ",res[i].x,res[i].y);
        return 0;
    }
    C

    $D$:

    题意:

    给你一个序列A,你可以随便选若干对$a_i ,a_j$,将这两个数替换成$a_{i} | a_{j}$和$a_{i} & a_{j}$,要求最大化$sum limits_{i=1}^{n}{a_{i}^{2}}$。

    题解:

    nt题,发现操作的实质就是把两个数各位的1扔到某一边,不改变两个数的和。

    那么要求的最大值相当于让序列的方差尽量大,我们直接把所有1扔到序列的一侧即可。

    代码:

    #include<bits/stdc++.h>
    #define maxn 200005
    #define maxm 500005
    #define inf 0x7fffffff
    #define ll long long
    #define rint register ll
    #define debug(x) cerr<<#x<<": "<<x<<endl
    #define fgx cerr<<"--------------"<<endl
    #define dgx cerr<<"=============="<<endl
     
    using namespace std;
    ll A[maxn],B[maxn],siz[maxn];
     
    inline ll read(){
        ll x=0,f=1; char c=getchar();
        for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
        for(;isdigit(c);c=getchar()) x=x*10+c-'0';
        return x*f;
    }
     
    int main(){
        ll n=read();
        for(ll i=1;i<=n;i++) A[i]=read();
        for(ll i=19;i>=0;i--)
            for(ll j=1;j<=n;j++) siz[i]+=((A[j]>>i)&1);
        for(ll i=19;i>=0;i--)
            for(ll j=1;j<=siz[i];j++) B[j]|=(1<<i);
        ll ans=0;
        for(ll i=1;i<=n;i++) ans+=(B[i]*B[i]);
        printf("%lld
    ",ans);
        return 0;
    }
    D

    $E$:

    题意:

    给你一个n个点m条边的有向图,每个点最多有两条出边。

    请你构造一种删掉不超过$frac{4}{7}n$个点使得图中不存在长度为2的路径的方案。

    $nleq 2 imes 10^5$。

    题解:

    直接按拓扑序遍历图,记录到达该点的最长路径长度dis,如果dis为2则删掉这个点。

    考虑证明,我们按dis值将点分成三类$V_0 ,V_1 ,V_2 $。

    由于$V_2$的边全部来自于$V_1$,而每个点最多两条出边,所以有$| V_2 |leq 2| V_1 |$。同理$| V_2 |leq 2| V_1 |leq 4| V_0 |$。

    那么有$| V_2 |+| V_1 |+| V_0 | leq 7 |V_0|$,脑补一下发现$| V_2 |leq frac{4}{7}(| V_2 |+| V_1 |+| V_0 |)=frac{4}{7}n$。

    真没想到,不是没想到做法,而是没想到证明。

    代码:

    #include<bits/stdc++.h>
    #define maxn 200005
    #define maxm 500005
    #define inf 0x7fffffff
    #define ll long long
    #define rint register int
    #define debug(x) cerr<<#x<<": "<<x<<endl
    #define fgx cerr<<"--------------"<<endl
    #define dgx cerr<<"=============="<<endl
     
    using namespace std;
    int dis[maxn],ans[maxn];
    vector<int> in[maxn]; 
     
    inline int read(){
        int x=0,f=1; char c=getchar();
        for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
        for(;isdigit(c);c=getchar()) x=x*10+c-'0';
        return x*f;
    }
     
    int main(){
        int T=read();
        while(T--){
            int n=read(),m=read(); ans[0]=0;
            for(int i=1;i<=n;i++) in[i].clear();
            for(int i=1;i<=m;i++){
                int u=read(),v=read();
                in[v].push_back(u); 
            }
            for(int u=1;u<=n;u++){
                dis[u]=0;            
                for(int j=0;j<in[u].size();j++) 
                    dis[u]=max(dis[u],dis[in[u][j]]+1);
                if(dis[u]==2) dis[u]=-1,ans[++ans[0]]=u;
            }
            printf("%d
    ",ans[0]);
            for(int i=1;i<=ans[0];i++) printf("%d ",ans[i]);
            printf("
    ");
        }
        return 0;
    }
    E

    $F$:

    题意:

    这是一道交互题。

    有一个长度为n的环,每个位置有一盏灯,初始都是灭的。现在你要和你的憨批朋友进行一场比赛。

    每次你任选k盏灯变成开的,然后你的憨批朋友选定一个位置p,将从p开始连续的k盏灯变成灭的。

    在每次操作之前你可以选择是否要结束比赛。

    你希望最大化结束比赛时亮的灯数目,而你的憨批朋友希望最小化该数目。

    假设你们都采用最优策略,请你构造出一种进行比赛的过程。

    每次你要输出k和你选择的k盏灯,然后系统会把你的憨批朋友选定的位置p告诉你。

    题解:

    假设我们已经有了x盏亮的灯,现在需要选定一个k使得x变大。

    那么显然操作之后任何亮的连续段长度不能超过k,发现至少有$lceil frac{n}{k} ceil$段。

    考虑到每段之间需要用一个灭的隔开,根据$亮+灭= n$的条件可以得到$x+k+lceil frac{n}{k} ceil= n$。

    解得$x= n-k-lceil frac{n}{k} ceil+1$(x变大之后的结果)。

    也就是说只要选定一个使$n-k-lceil frac{n}{k} ceil+1$最大的k,就可以一直用固定的k操作了。

    那么将环每k个标记一下永远不选,然后用个set什么的维护当前灭的位置集合就行了。

    注意交互题在每个输出后面需要整一个$fflush(stdout)$。

    套路:

    • 推式子时:注意用边界卡出取值范围。

    代码:

    #include<bits/stdc++.h>
    #define maxn 200005
    #define maxm 500005
    #define inf 0x7fffffff
    #define ll long long
    #define rint register int
    #define debug(x) cerr<<#x<<": "<<x<<endl
    #define fgx cerr<<"--------------"<<endl
    #define dgx cerr<<"=============="<<endl
     
    using namespace std;
    set<int> s; int ok[maxn];
     
    inline int read(){
        int x=0,f=1; char c=getchar();
        for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
        for(;isdigit(c);c=getchar()) x=x*10+c-'0';
        return x*f;
    }
     
    inline int frac(int a,int b){return (a%b==0)?(a/b):(a/b+1);}
     
    int main(){
        int n=read(),k=n,x=0;
        for(int i=1;i<=n;i++)
            if(x<=n-i-frac(n,i)+1)
                x=n-i-frac(n,i)+1,k=i;
        for(int i=1;i<=n;i+=k)
            ok[min(i+k-1,n)]=-1;
        for(int i=1;i<=n;i++)
            if(ok[i]!=-1)
                s.insert(i);
        //cout<<x<<endl; 
        while(s.size()>=k){
            printf("%d",k);
            for(int i=1;i<=k;i++){
                auto it=s.begin();
                printf(" %d",*it),s.erase(it);
            }
            printf("
    "),fflush(stdout); 
            int p=read(); if(p==-1) exit(0);
            for(int i=1;i<=k;i++,p=p%n+1) 
                if(ok[p]!=-1)
                    s.insert(p);
        }
        printf("0
    "),fflush(stdout);
        return 0;
    }
    F

    $G$:

    题意:

    有一个$n imes m$的网格,铺满了多米诺骨牌。你可以任选一个骨牌拿走,然后自由移动剩下的骨牌。

    一个骨牌只能沿平行于长边的方向移动,且移动后占的格必须和移动前占的格有交(只能移动一次)。

    求有多少种拿走并移动的方案,两种方案不同当且仅当最后棋盘上空的两个格不同。

    $nmleq 10^{5}$。

    题解:

    考虑一个直观的想法:如果v骨牌动了之后u能动,那么连边$(u,v)$。

    但这样直接连边不能确定移动方向,导致一条路径不一定能从头移动到尾。

    考虑到一般铺骨牌的问题都可以把原图黑白染色后处理,而且这个题最后空出来的格一定是一黑一白。

    于是我们将这张图黑白染色,在两个同色格之间按上述方法连边。每条边$(u,v)$表示如果v空出来了,那么移动一次后u能空出来。

    容易发现此时每个点最多有一条出边,且有一个结论:此时连出来的必然是一个森林。

    (证明:考虑在这个图里随便拿骨牌拼一个环,手画一下发现环内一定有奇数个点,所以这种方案不合法)

    那么现在可以考虑计算答案了。发现一对黑白点$(u,v)$能作为答案当且仅当它们分别能走到$(w1,w2)$,满足w1与w2被同一个骨牌覆盖。

    翻译一下:有两棵树,求有几对点对$(u,v)$,满足u在第一棵树上的某个祖先与v在第二棵树上的某个祖先相同。

    这是个比较简单的数据结构问题,考虑第一棵树上的点u在第二棵树上有多少个合法的v,容易发现就是u所有祖先在第二棵树上的子树的并。

    那么实际上就是维护区间加减和区间非零的个数,直接用线段树维护区间最小值和最小值个数即可。

    复杂度$O(nmlog{nm})$。

    套路:

    • 网格图上只与相邻两格有关的问题$ ightarrow$黑白染色。
    • 构造了一个图但是没什么性质$ ightarrow$改成一棵树。

    代码:

    #include<bits/stdc++.h>
    #define maxn 200005
    #define maxm 500005
    #define inf 0x7fffffff
    #define ll long long
    #define rint register int
    #define debug(x) cerr<<#x<<": "<<x<<endl
    #define fgx cerr<<"--------------"<<endl
    #define dgx cerr<<"=============="<<endl
     
    using namespace std;
    int fa[2][maxn],to[2][maxn],nxt[2][maxn],hd[2][maxn]; 
    int dfn[2][maxn],P[2][maxn],siz[2][maxn],num[2];
    int trmn[maxn<<2],trsz[maxn<<2],trlz[maxn<<2],cnt[2];
    char str[maxn]; map<int,int> id[maxn]; ll ans;
     
    inline int read(){
        int x=0,f=1; char c=getchar();
        for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
        for(;isdigit(c);c=getchar()) x=x*10+c-'0';
        return x*f;
    }
     
    inline void addedge(int u,int v,int op){fa[op][u]=v,to[op][++cnt[op]]=u,nxt[op][cnt[op]]=hd[op][v],hd[op][v]=cnt[op];}
    inline void dfs(int u,int op){
        dfn[op][u]=++num[op],siz[op][u]=1;
        for(int i=hd[op][u];i;i=nxt[op][i])
            {int v=to[op][i];dfs(v,op);siz[op][u]+=siz[op][v];}
    }
     
    inline void pushup(int k){
        if(trmn[k<<1]==trmn[k<<1|1]) trmn[k]=trmn[k<<1],trsz[k]=trsz[k<<1]+trsz[k<<1|1];
        else if(trmn[k<<1]<trmn[k<<1|1]) trmn[k]=trmn[k<<1],trsz[k]=trsz[k<<1];
        else trmn[k]=trmn[k<<1|1],trsz[k]=trsz[k<<1|1];
    }
    inline void pushdown(int k){
        if(trlz[k]){
            int tp=trlz[k]; trlz[k]=0;
            trlz[k<<1]+=tp,trlz[k<<1|1]+=tp;
            trmn[k<<1]+=tp,trmn[k<<1|1]+=tp;
        }
    }
    inline void build(int l,int r,int k){
        trmn[k]=0,trsz[k]=r-l+1;
        if(l==r) return; int mid=l+r>>1;
        build(l,mid,k<<1),build(mid+1,r,k<<1|1);
    }
    inline void add(int x,int y,int z,int l,int r,int k){
        if(x<=l && r<=y){trmn[k]+=z,trlz[k]+=z;return;}
        pushdown(k); int mid=l+r>>1;
        if(x<=mid) add(x,y,z,l,mid,k<<1);
        if(y>mid) add(x,y,z,mid+1,r,k<<1|1);
        pushup(k);
    }
     
    inline void Dfs(int u){
        add(dfn[1][u],dfn[1][u]+siz[1][u]-1,1,1,num[1],1);
        ans+=(ll)(num[0]-((trmn[1]==0)?trsz[1]:0));
        for(int i=hd[0][u];i;i=nxt[0][i]) Dfs(to[0][i]);
        add(dfn[1][u],dfn[1][u]+siz[1][u]-1,-1,1,num[1],1);
    }
     
    int main(){
        int n=read(),m=read(),tot=0;
        for(int i=1;i<=n;i++){
            scanf("%s",str+1);
            for(int j=1;j<=m;j++){
                if(str[j]=='L') id[i][j]=id[i][j+1]=++tot; 
                if(str[j]=='U') id[i][j]=id[i+1][j]=++tot;
            }
        }    
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++){
                if(id[i][j]==id[i][j+1]){
                    if((i+j)&1){
                        if(j+2<=m) addedge(id[i][j],id[i][j+2],1);
                        if(j-1>=1) addedge(id[i][j+1],id[i][j-1],0);
                    }
                    else{
                        if(j+2<=m) addedge(id[i][j],id[i][j+2],0);
                        if(j-1>=1) addedge(id[i][j+1],id[i][j-1],1);
                    }
                }
                if(id[i][j]==id[i+1][j]){
                    if((i+j)&1){
                        if(i+2<=n) addedge(id[i][j],id[i+2][j],1);
                        if(i-1>=1) addedge(id[i+1][j],id[i-1][j],0);
                    }
                    else{
                        if(i+2<=n) addedge(id[i][j],id[i+2][j],0);
                        if(i-1>=1) addedge(id[i+1][j],id[i-1][j],1);
                    }
                }
            }
        for(int k=0;k<2;k++) for(int i=1;i<=tot;i++) if(!fa[k][i]) dfs(i,k);
        build(1,num[1],1);
        for(int i=1;i<=tot;i++) if(!fa[0][i]) Dfs(i);
        printf("%lld
    ",ans);
        return 0;
    }
    G

    $H$:

    题意:

    给你一个电路板,上下各m个接口,左右各n个接口,中间有$n imes m$个节点。每个接口为红色或蓝色。

    你希望用若干条导线连接这些接口,满足:

    • 导线两端点必须连一个红色接口和一个蓝色接口,每个接口最多连一条导线。
    • 导线的任何一段必须是竖直或平行的,且只能在节点处拐弯。
    • 任何两根导线都不能有公共长度,但可以有公共节点。

    现在有q次操作,每次操作将上/下/左/右位于$[L,R]$之间的接口颜色取反(红变蓝,蓝变红)。

    每次操作结束后你需要输出此时的电路板最多可以连接多少根导线。

    $n,m,qleq 10^{5}$。

    题解:

    显然如果没有数据范围要求的话可以直接连边跑最大流。

    由于最大流等于最小割,相当于求最少割掉多少条边使得红/蓝不连通。

    考虑一条切割路径,如果它拐弯了,那么总存在一种方式将它替换成一个整行/整列的切割和若干个在端点处的切割,且替换后不会增加答案。

    那么这张图的最小割之一就是由一堆整行/整列的切割和一堆端点处的切割组成的。(注意有整行切割就不能有整列切割,反之亦然)

    此时我们就可以弄两个线性dp来计算答案了,大概是$dp(i,0/1)$表示切割完前i个且前面传过来的颜色是红/蓝的最小代价。

    考虑支持修改,由于这个dp是区间合并的形式,我们可以用线段树来维护它。

    每个线段树节点$tr(l,r,0/1,0/1)$表示将区间$[l,r]$切割完,左边/右边传出去的颜色是红/蓝的最小代价。

    由于修改是区间取反的形式,我们还需要加一维表示(以上下为例)上下都不取反/上取反/下取反/上下都取反的答案。

    常数巨大,比较难写。复杂度$O(qlog{(n+m)})$。

    套路:

    • 网格图最小割$ ightarrow$可以dp算。
    • 形如区间合并的dp$ ightarrow$直接用线段树维护。

    代码:

    #include<bits/stdc++.h>
    #define maxn 100005
    #define maxm 500005
    #define inf 0x7fffffff
    #define ll long long
    #define rint register int
    #define debug(x) cerr<<#x<<": "<<x<<endl
    #define fgx cerr<<"--------------"<<endl
    #define dgx cerr<<"=============="<<endl
     
    using namespace std;
    int tot,S; char A[2][maxn],B[2][maxn];
    char str[maxn],str0[2][maxn],str1[2][maxn];
    struct SegmentTree{
        ll tr[maxn<<2][4][2][2],lz[maxn<<2];
        inline void rev(int k,int lz){
            for(rint i=0;i<2;i++) 
                for(rint j=0;j<2;j++){
                    if(lz==1) swap(tr[k][0][i][j],tr[k][1][i][j]),swap(tr[k][2][i][j],tr[k][3][i][j]);
                    if(lz==2) swap(tr[k][0][i][j],tr[k][2][i][j]),swap(tr[k][1][i][j],tr[k][3][i][j]);
                    if(lz==3) swap(tr[k][0][i][j],tr[k][3][i][j]),swap(tr[k][1][i][j],tr[k][2][i][j]);
                }
        }
        inline void pushup(ll k){
            for(rint t=0;t<4;t++) 
                for(rint l=0;l<2;l++) 
                    for(rint r=0;r<2;r++){
                        tr[k][t][l][r]=1ll<<61;
                        for(rint lc=0;lc<2;lc++) 
                            for(rint rc=0;rc<2;rc++)
                                tr[k][t][l][r]=min(tr[k][t][l][r],tr[k<<1][t][l][lc]+tr[k<<1|1][t][rc][r]+((lc!=rc)?tot:0));
                    }
        }
        inline void pushdown(int k){
            if(lz[k]){
                lz[k<<1]^=lz[k],lz[k<<1|1]^=lz[k];
                rev(k<<1,lz[k]),rev(k<<1|1,lz[k]),lz[k]=0;
            }
        }
        inline void build(int l,int r,int k){
            if(l==r){
                ll m=S-tot;
                if(l==0){
                    ll n=tot,res=0; 
                    for(int i=1;i<=n;i++) res+=(str1[0][i]=='B');
                    for(int i=0;i<4;i++) tr[k][i][0][0]=n-res,tr[k][i][1][1]=res;
                } 
                else if(l==m+1){
                    ll n=tot,res=0; 
                    for(int i=1;i<=n;i++) res+=(str1[1][i]=='B');
                    for(int i=0;i<4;i++) tr[k][i][0][0]=n-res,tr[k][i][1][1]=res;
                }
                else{
                    int t1=(str0[0][l]=='B'),t2=(str0[1][l]=='B');
                    tr[k][0][0][0]=(t1^1)+(t2^1),tr[k][0][1][1]=t1+t2;
                    tr[k][1][0][0]=t1+(t2^1),tr[k][1][1][1]=(t1^1)+t2;
                    tr[k][2][0][0]=(t1^1)+t2,tr[k][2][1][1]=t1+(t2^1);
                    tr[k][3][0][0]=t1+t2,tr[k][3][1][1]=(t1^1)+(t2^1);
                }
                return;
            }
            int mid=l+r>>1; 
            build(l,mid,k<<1),build(mid+1,r,k<<1|1);
            pushup(k); 
        }
        inline void upd0(int x,int y,int l,int r,int k){
            if(l==r){
                for(rint i=0;i<4;i++)
                    tr[k][i][1][1]+=y,tr[k][i][0][0]=tot-tr[k][i][1][1];
                return;
            }
            pushdown(k); int mid=l+r>>1; 
            if(x<=mid) upd0(x,y,l,mid,k<<1); 
            else upd0(x,y,mid+1,r,k<<1|1); 
            pushup(k);
        } 
        inline void upd1(int x,int y,int z,int l,int r,int k){
            if(x<=l && r<=y){lz[k]^=z,rev(k,z);return;}
            pushdown(k); int mid=l+r>>1;
            if(x<=mid) upd1(x,y,z,l,mid,k<<1);
            if(y>mid) upd1(x,y,z,mid+1,r,k<<1|1);
            pushup(k);
        }
    }trn,trm;
     
    struct SegmentTree_au{
        ll tr[maxn<<2],lz[maxn<<2];
        inline void pushdown(int k,int l){
            if(lz[k]){
                int rl=l>>1; lz[k]=0;
                lz[k<<1]^=1,tr[k<<1]=l-rl-tr[k<<1];
                lz[k<<1|1]^=1,tr[k<<1|1]=rl-tr[k<<1|1];
            }
        } 
        inline void build(int l,int r,int k){
            if(l==r){tr[k]=(str[l]=='B');return;}
            int mid=l+r>>1; 
            build(l,mid,k<<1),build(mid+1,r,k<<1|1);
            tr[k]=tr[k<<1]+tr[k<<1|1];
        }
        inline void upd(int x,int y,int l,int r,int k){
            if(x<=l && r<=y){tr[k]=r-l+1-tr[k],lz[k]^=1;return;}
            pushdown(k,r-l+1); int mid=l+r>>1; 
            if(x<=mid) upd(x,y,l,mid,k<<1); 
            if(y>mid) upd(x,y,mid+1,r,k<<1|1);
            tr[k]=tr[k<<1]+tr[k<<1|1]; 
        }
    }L,R,U,D;
     
    inline ll read(){
        ll x=0,f=1; char c=getchar();
        for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
        for(;isdigit(c);c=getchar()) x=x*10+c-'0';
        return x*f;
    }
     
    int main(){
        memset(trm.tr,63,sizeof(trm.tr));
        memset(trn.tr,63,sizeof(trn.tr));
        ll n=read(),m=read(),q=read(),ans=1ll<<62; S=n+m;
        scanf("%s",A[0]+1),scanf("%s",A[1]+1);
        scanf("%s",B[0]+1),scanf("%s",B[1]+1);
        memcpy(str1,A,sizeof(A)),memcpy(str0,B,sizeof(B)); 
        tot=n,trm.build(0,m+1,1);
        memcpy(str0,A,sizeof(A)),memcpy(str1,B,sizeof(B));
        tot=m,trn.build(0,n+1,1); 
        memcpy(str,A[0],sizeof(A[0])),L.build(1,n,1);
        memcpy(str,A[1],sizeof(A[1])),R.build(1,n,1);
        memcpy(str,B[0],sizeof(B[0])),U.build(1,m,1);
        memcpy(str,B[1],sizeof(B[1])),D.build(1,m,1);
        for(rint i=0;i<2;i++) 
            for(rint j=0;j<2;j++)
                ans=min(ans,min(trn.tr[1][0][i][j],trm.tr[1][0][i][j]));
        printf("%lld
    ",ans);
        while(q--){
            char ch; cin>>ch;
            int l=read(),r=read(); ans=1ll<<62;
            if(ch=='L'){
                int res=-L.tr[1];L.upd(l,r,1,n,1),res+=L.tr[1];
                tot=n,trm.upd0(0,res,0,m+1,1);
                tot=m,trn.upd1(l,r,1,0,n+1,1);
            } 
            if(ch=='R'){
                int res=-R.tr[1];R.upd(l,r,1,n,1),res+=R.tr[1];
                tot=n,trm.upd0(m+1,res,0,m+1,1);
                tot=m,trn.upd1(l,r,2,0,n+1,1);
            } 
            if(ch=='U'){
                int res=-U.tr[1];U.upd(l,r,1,m,1),res+=U.tr[1];
                tot=m,trn.upd0(0,res,0,n+1,1);
                tot=n,trm.upd1(l,r,1,0,m+1,1);
            } 
            if(ch=='D'){
                int res=-D.tr[1];D.upd(l,r,1,m,1),res+=D.tr[1];
                tot=m,trn.upd0(n+1,res,0,n+1,1);
                tot=n,trm.upd1(l,r,2,0,m+1,1);
            } 
            for(rint i=0;i<2;i++) 
                for(rint j=0;j<2;j++)
                    ans=min(ans,min(trn.tr[1][0][i][j],trm.tr[1][0][i][j]));
            printf("%lld
    ",ans);
        }
        return 0;
    }
    H
  • 相关阅读:
    js扩展Date对象的方法,格式化日期格式(prototype)
    JSP中的普通路径写法
    工作方向与目标
    Cookie工具类(获取cookie,设置cookie)
    读取普通java web项目下的WEB-INF目录下的配置文件(application.xml,xx.properties等配置文件)
    js单选和全选
    exits 和no exits
    Linux配置nginux
    Java读取利用java.util类Properties读取resource下的properties属性文件
    vue-devtools vue调试工具
  • 原文地址:https://www.cnblogs.com/YSFAC/p/13181101.html
Copyright © 2020-2023  润新知