2021.8.14考试总结[NOIP模拟39]
T1 打地鼠
全场就俩人没切,还有一个是忘关$freopen$了。
$code:$
1 #include<bits/stdc++.h> 2 #define rin register signed 3 using namespace std; 4 const int NN=2e3+5; 5 int n,k,pre[NN][NN],ans; 6 char ch[NN]; 7 inline int read(){ 8 int x=0,f=1; char ch=getchar(); 9 while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } 10 while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } 11 return x*f; 12 } 13 inline void write(int x,char sp){ 14 char ch[25]; int len=0; 15 if(x<0){ putchar('-'); x=~x+1; } 16 do{ ch[len++]=x%10+(1<<5)+(1<<4); x/=10; }while(x); 17 for(int i=len-1;~i;i--) putchar(ch[i]); putchar(sp); 18 } 19 signed main(){ 20 n=read(); k=read(); 21 for(rin i=1;i<=n;i++){ 22 scanf("%s",ch+1); 23 for(rin j=1;j<=n;j++) 24 pre[i][j]=pre[i][j-1]+(ch[j]=='1'); 25 for(rin j=1;j<=n;j++) pre[i][j]+=pre[i-1][j]; 26 } 27 for(int i=0;i<=n-k;i++) 28 for(int j=0;j<=n-k;j++) 29 ans=max(ans,pre[i+k][j+k]+pre[i][j]-pre[i][j+k]-pre[i+k][j]); 30 write(ans,'\n'); 31 return 0; 32 }
T2 竞赛图
竞赛图缩点后会形成一条链,因此对一个不强联通的子图$S$,必然存在且只有一个强联通的子图$T$,满足$S-T$中点的边都是$S \to T$的。
考虑通过这个性质用强联通子图更新不强联通子图。预处理出每个子集所有点出边的交集即可。
$code:$
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int NN=24; 4 int t,n,to[1<<NN],S,ans; 5 bool is[1<<NN]; 6 inline int read(){ 7 int x=0,f=1; char ch=getchar(); 8 while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } 9 while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } 10 return x*f; 11 } 12 inline void write(int x,char sp){ 13 char ch[20]; int len=0; 14 if(x<0){ putchar('-'); x=~x+1; } 15 do{ ch[len++]=x%10+(1<<5)+(1<<4); x/=10; }while(x); 16 for(int i=len-1;~i;i--) putchar(ch[i]); putchar(sp); 17 } 18 signed main(){ 19 t=read(); 20 while(t--){ 21 memset(to,0,sizeof(to)); memset(is,1,sizeof(is)); 22 n=read(); to[0]=S=(1<<n)-1; ans=0; 23 for(int i=0;i<n;i++) for(int j=0;j<n;j++) 24 if(read()) to[1<<i]|=1<<j; 25 for(int i=1;i<=S;i++) to[i]=to[i^(i&(-i))]&to[i&(-i)]; 26 for(int i=1;i<=S;i++) 27 if(is[i]) 28 for(int j=to[i];j;j=(j-1)&to[i]) is[i|j]=0; 29 for(int i=0;i<=S;i++) if(is[i]) ++ans; 30 write(ans,'\n'); 31 } 32 return 0; 33 }
T3 糖果
神仙$DP$,没改出来,钴了。
T4 树
$\textit{NOI D1T1}$原题,把黑白边反过来了。
树剖,边权下放,每次修改将路径上点打上时间戳,发现黑边数量其实就是相邻两边时间戳不同的边对数。
一开始建树时要保证所有点的时间戳不同。
$code:$
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int NN=3e5+5; 4 int q,n,idx,to[NN<<1],nex[NN<<1],head[NN],tp,x,y; 5 int siz[NN],son[NN],top[NN],dfn[NN],fa[NN],dep[NN],cnt,tim; 6 inline int read(){ 7 int x=0,f=1; char ch=getchar(); 8 while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } 9 while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } 10 return x*f; 11 } 12 inline void write(int x,char sp){ 13 char ch[20]; int len=0; 14 if(x<0){ putchar('-'); x=~x+1; } 15 do{ ch[len++]=x%10+(1<<5)+(1<<4); x/=10; }while(x); 16 for(int i=len-1;~i;i--) putchar(ch[i]); putchar(sp); 17 } 18 inline void add(int a,int b){ 19 to[++idx]=b; nex[idx]=head[a]; head[a]=idx; 20 to[++idx]=a; nex[idx]=head[b]; head[b]=idx; 21 } 22 void dfs1(int s,int f){ 23 siz[s]=1; fa[s]=f; dep[s]=dep[f]+1; 24 for(int i=head[s];i;i=nex[i]){ 25 int v=to[i]; 26 if(v==f) continue; 27 dfs1(v,s); 28 siz[s]+=siz[v]; 29 if(siz[v]>siz[son[s]]) son[s]=v; 30 } 31 } 32 void dfs2(int s,int t){ 33 dfn[s]=++cnt; top[s]=t; 34 if(!son[s]) return; 35 dfs2(son[s],t); 36 for(int i=head[s];i;i=nex[i]){ 37 int v=to[i]; 38 if(v!=fa[s]&&v!=son[s]) dfs2(v,v); 39 } 40 } 41 struct segment_tree{ 42 #define ld rt<<1 43 #define rd (rt<<1)|1 44 int sum[NN<<2],lc[NN<<2],rc[NN<<2],laz[NN<<2]; 45 void pushup(int rt){ 46 sum[rt]=sum[ld]+sum[rd]+(rc[ld]!=lc[rd]); 47 lc[rt]=lc[ld]; rc[rt]=rc[rd]; 48 } 49 void pushdown(int rt){ 50 if(!laz[rt]) return; 51 laz[ld]=laz[rt]; laz[rd]=laz[rt]; 52 sum[ld]=sum[rd]=0; 53 lc[ld]=lc[rd]=rc[ld]=rc[rd]=laz[rt]; 54 laz[rt]=0; 55 } 56 void build(int rt,int l,int r){ 57 if(l==r){ lc[rt]=rc[rt]=l; return; } 58 int mid=l+r>>1; 59 build(ld,l,mid); 60 build(rd,mid+1,r); 61 pushup(rt); 62 } 63 void modify(int rt,int l,int r,int opl,int opr,int v){ 64 if(l>=opl&&r<=opr){ 65 sum[rt]=0; 66 lc[rt]=rc[rt]=laz[rt]=v; 67 return; 68 } 69 pushdown(rt); 70 int mid=l+r>>1; 71 if(opl<=mid) modify(ld,l,mid,opl,opr,v); 72 if(opr>mid) modify(rd,mid+1,r,opl,opr,v); 73 pushup(rt); 74 } 75 int query(int rt,int l,int r,int opl,int opr){ 76 if(l>=opl&&r<=opr) return sum[rt]; 77 pushdown(rt); 78 int mid=l+r>>1; 79 if(opr<=mid) return query(ld,l,mid,opl,opr); 80 else if(opl>mid) return query(rd,mid+1,r,opl,opr); 81 else return query(ld,l,mid,opl,mid)+query(rd,mid+1,r,mid+1,opr)+(lc[rd]!=rc[ld]); 82 } 83 int look(int rt,int l,int r,int pos){ 84 if(l==r) return lc[rt]; 85 pushdown(rt); 86 int mid=l+r>>1; 87 if(pos<=mid) return look(ld,l,mid,pos); 88 else return look(rd,mid+1,r,pos); 89 } 90 }s; 91 void UPD(int x,int y){ 92 int fx=top[x],fy=top[y]; ++tim; 93 while(fx!=fy) 94 if(dep[fx]>dep[fy]){ 95 s.modify(1,1,n,dfn[fx],dfn[x],tim); 96 x=fa[fx]; fx=top[x]; 97 } 98 else{ 99 s.modify(1,1,n,dfn[fy],dfn[y],tim); 100 y=fa[fy]; fy=top[y]; 101 } 102 if(dep[x]>dep[y]) s.modify(1,1,n,dfn[y],dfn[x],tim); 103 else s.modify(1,1,n,dfn[x],dfn[y],tim); 104 } 105 int ANS(int x,int y){ 106 int ans=0,fx=top[x],fy=top[y]; 107 while(fx!=fy) 108 if(dep[fx]>dep[fy]){ 109 ans+=s.query(1,1,n,dfn[fx],dfn[x]); 110 ans+=(s.look(1,1,n,dfn[fx])!=s.look(1,1,n,dfn[fa[fx]])); 111 x=fa[fx]; fx=top[x]; 112 } 113 else{ 114 ans+=s.query(1,1,n,dfn[fy],dfn[y]); 115 ans+=(s.look(1,1,n,dfn[fy])!=s.look(1,1,n,dfn[fa[fy]])); 116 y=fa[fy]; fy=top[y]; 117 } 118 if(dep[x]<dep[y]) ans+=s.query(1,1,n,dfn[x],dfn[y]); 119 else ans+=s.query(1,1,n,dfn[y],dfn[x]); 120 return ans; 121 } 122 signed main(){ 123 tim=n=read(); 124 for(int i=1;i<n;i++) add(read(),read()); 125 dfs1(1,0); dfs2(1,1); 126 s.build(1,1,n); 127 q=read(); 128 while(q--){ 129 tp=read(); x=read(); y=read(); 130 if(tp==1) UPD(x,y); 131 if(tp==2) write(ANS(x,y),'\n'); 132 } 133 return 0; 134 }