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
原文地址:https://www.cnblogs.com/YSFAC/p/13181101.html