# APCS 2021/11題解
## ==修補圍籬==
### <font color="0E81A6">題目</font>
[修補圍籬](https://zerojudge.tw/ShowProblem?problemid=g595)
### <font color="0E81A6">核心</font>
陣列、條件判斷
### <font color="0E81A6">思路</font>
陣列頭尾建一個超高圍籬。
```c++=
#include<bits/stdc++.h>
using namespace std;
#define oo 1000
int main()
{
int n,fence[102];
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",fence+i);
fence[0]=oo,fence[n+1]=oo;
int cost=0;
for(int i=1;i<=n;i++)
{
if(fence[i]==0) cost+=min(fence[i-1],fence[i+1]);
}
printf("%d\n",cost);
}
```
## ==動線安排==
### <font color="0E81A6">題目</font>
[動線安排](https://zerojudge.tw/ShowProblem?problemid=g596)
### <font color="0E81A6">核心</font>
搞人、模擬
### <font color="0E81A6">思路</font>
純屬搞人心態。
```c++=
#include<bits/stdc++.h>
using namespace std;
int m,n,h,r,c,t,arr[100][100]={},mx=0;
bool findNeighbor(int x,int y,int d) //up 0 down 1 left 2 right 3
{
if(d==0)
{
for(int i=x-1;i>=0;i--) if(arr[i][y]==-1) return 1;
return 0;
}
else if(d==1)
{
for(int i=x+1;i<m;i++) if(arr[i][y]==-1) return 1;
return 0;
}
else if(d==2)
{
for(int i=y-1;i>=0;i--) if(arr[x][i]==-1) return 1;
return 0;
}
else
{
for(int i=y+1;i<n;i++) if(arr[x][i]==-1) return 1;
return 0;
}
}
void rmv(int x,int y,int d)
{
if(d==0)
{
for(int i=x-1;i>=0;i--)
{
if(arr[i][y]==-1) return;
else if(arr[i][y]>0) arr[i][y]--;
}
}
else if(d==1)
{
for(int i=x+1;i<m;i++)
{
if(arr[i][y]==-1) return;
else if(arr[i][y]>0) arr[i][y]--;
}
}
else if(d==2)
{
for(int i=y-1;i>=0;i--)
{
if(arr[x][i]==-1) return;
else if(arr[x][i]>0) arr[x][i]--;
}
}
else
{
for(int i=y+1;i<n;i++)
{
if(arr[x][i]==-1) return;
else if(arr[x][i]>0) arr[x][i]--;
}
}
}
void cutWire(int x,int y,int d)
{
if(d==0)
{
for(int i=x-1;i>=0;i--)
{
if(arr[i][y]==0||arr[i][y]==-1) return;
else if(arr[i][y]>0) arr[i][y]--;
}
}
else if(d==1)
{
for(int i=x+1;i<m;i++)
{
if(arr[i][y]==-1||arr[i][y]==0) return;
else if(arr[i][y]>0) arr[i][y]--;
}
}
else if(d==2)
{
for(int i=y-1;i>=0;i--)
{
if(arr[x][i]==-1||arr[x][i]==0) return;
else if(arr[x][i]>0) arr[x][i]--;
}
}
else
{
for(int i=y+1;i<n;i++)
{
if(arr[x][i]==-1||arr[x][i]==0) return;
else if(arr[x][i]>0) arr[x][i]--;
}
}
}
void add(int x,int y,int d){//up 0 down 1 left 2 right 3
if(d==0){
for(int i=x-1;i>=0;i--){
if(arr[i][y]==-1)return;
else arr[i][y]++;
}
}
else if(d==1){
for(int i=x+1;i<m;i++){
if(arr[i][y]==-1)return;
else arr[i][y]++;
}
}
else if(d==2){
for(int i=y-1;i>=0;i--){
if(arr[x][i]==-1)return;
else arr[x][i]++;
}
}
else{
for(int i=y+1;i<n;i++){
if(arr[x][i]==-1)return;
else arr[x][i]++;
}
}
}
int cnt()
{
int ans=0;
for(int i=0;i<m;i++)
{
for(int j=0;j<n;j++) if(arr[i][j]!=0) ans++;
}
return ans;
}
int main()
{
ios::sync_with_stdio(0),cin.tie(0);
cin>>m>>n>>h;
while(h--)
{
cin>>r>>c>>t;
if(t==0)
{
if(arr[r][c]!=0)
{
for(int i=0;i<4;i++) if(findNeighbor(r,c,i)) cutWire(r,c,i);
}
arr[r][c]=-1;
for(int i=0;i<4;i++) if(findNeighbor(r,c,i)) add(r,c,i);
}
else
{
arr[r][c]=0;
for(int i=0;i<4;i++) if(findNeighbor(r,c,i)) rmv(r,c,i);
}
mx=max(mx,cnt());
}
cout<<mx<<"\n"<<cnt();
}
```
## ==生產線==
### <font color="0E81A6">題目</font>
[生產線](https://zerojudge.tw/ShowProblem?problemid=g597)
### <font color="0E81A6">核心</font>
BIT、前綴和
### <font color="0E81A6">思路</font>
[BIT教學](https://oi-wiki.org/ds/fenwick/)
學會之後這題就迎刃而解了。
```c++=
#include<bits/stdc++.h>
using namespace std;
#define N 200005
int n,m,machine[N];
long long ans=0;
bool cmp(int a,int b)
{
return a>b;
}
struct BIT
{
int sz;
vector<int> dat;
void init(int n)
{
sz=n;
dat.assign(sz+2,0);
return;
}
void upd(int id,int x)
{
for(int i=id;i<=sz;i+=i&-i) dat[i]+=x;
return;
}
int sum(int id)
{
int ans=0;
for(int i=id;i>0;i-=i&-i) ans+=dat[i];
return ans;
}
}bit;
int main()
{
scanf("%d%d",&n,&m);
bit.init(n);
int a,b,w;
while(m--)
{
scanf("%d%d%d",&a,&b,&w);
bit.upd(a,w);
bit.upd(b+1,-w);
}
vector<int> v;
for(int i=1;i<=n;i++) v.push_back(bit.sum(i));
sort(v.begin(),v.end(),cmp);
for(int i=0;i<n;i++) scanf("%d",machine+i);
sort(machine,machine+n);
for(int i=0;i<n;i++) ans+=machine[i]*v[i];
printf("%lld\n",ans);
}
```
## ==真假子圖==
### <font color="0E81A6">題目</font>
[真假子圖](https://zerojudge.tw/ShowProblem?problemid=g598)
### <font color="0E81A6">核心</font>
並查集、二分圖
### <font color="0E81A6">思路</font>
這題運用到填色和並查集的觀念,屬實漂亮。
```c++=
#include<bits/stdc++.h>
using namespace std;
#define N 20005
#define int long long
int parent[N],color[N]={0},rk[N];
vector<int> edge[N];
int other(int s){return (s%2)?s+1:s-1;}
void init(int col)
{
for(int i=1;i<=col;i++) parent[i]=i,rk[i]=0;
}
void dfs(int id,int col)
{
color[id]=col;
for(auto i:edge[id])
{
if(!color[i]) dfs(i,other(col));
}
}
int findp(int u)
{
if(parent[u]==u) return u;
return parent[u]=findp(parent[u]);
}
void join(int u,int v)
{
int r1=findp(u),r2=findp(v);
if(r1==r2) return;
if(rk[r1]<rk[r2]) swap(r1,r2);
parent[r2]=r1;
if(rk[r1]==rk[r2]) rk[r1]++;
return;
}
signed main()
{
int n,m,p,k,u,v;
scanf("%lld%lld",&n,&m);
for(int i=0;i<m;i++)
{
scanf("%lld%lld",&u,&v);
edge[u].push_back(v);
edge[v].push_back(u);
}
int now=1;
for(int i=0;i<n;i++)
{
if(!color[i]) dfs(i,now),now+=2;
}
vector<int> ans;
scanf("%lld%lld",&p,&k);
for(int i=1;i<=p;i++)
{
bool mistake=false;
init(now);
for(int j=0;j<k;j++)
{
scanf("%lld%lld",&u,&v);
if(mistake) continue;
if(findp(color[u])==findp(color[v])) mistake=true,ans.push_back(i);
else
{
join(color[u],other(color[v]));
join(color[v],other(color[u]));
}
}
}
for(int i:ans) printf("%lld\n",i);
}
```