2021“MINIEYE杯”中国大学生算法设计超级联赛(4)1008.Lawn of the Dead (线段树)
-
题意:有一个\(n\)x\(m\)的矩阵,有\(k\)个炸弹分布在矩阵上,你最开始在\((1,1)\)的位置,每次可以向下或者向右走到空的单位,问你最多能到达多少单位(假设你可以从起点开始走无限次).
-
题解:这题的数据范围很大,不好处理.假如某个位置\((x,y)\)有炸弹,并且\((x-1,y+1)\)到\((x-1,y+1+k)\)这段位置全有炸弹,那么容易知道:\((x,y+1)\)到\((x,y+1+k)\)是不能到达的,那么每次只考虑当前行和上一行的情况,用两个线段树维护连续区间和查询即可.
-
代码:
#include <bits/stdc++.h> #define ll long long #define fi first #define se second #define pb push_back #define me memset #define rep(a,b,c) for(int a=b;a<=c;++a) #define per(a,b,c) for(int a=b;a>=c;--a) const int N = 1e6 + 10; const int mod = 1e9 + 7; const int INF = 0x3f3f3f3f; using namespace std; typedef pair<int,int> PII; typedef pair<ll,ll> PLL; ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;} ll lcm(ll a,ll b) {return a/gcd(a,b)*b;} int n,m,k; vector<int> col[N]; struct misaka{ int l,r; int cnt; int lazy; }tr[2][N<<4]; void push_up(int id,int u){ tr[id][u].cnt=tr[id][u<<1].cnt+tr[id][u<<1|1].cnt; } void push_down(int id,int u){ if(tr[id][u].lazy==-1) return; tr[id][u<<1].cnt=(tr[id][u<<1].r-tr[id][u<<1].l+1)*tr[id][u].lazy; tr[id][u<<1|1].cnt=(tr[id][u<<1|1].r-tr[id][u<<1|1].l+1)*tr[id][u].lazy; tr[id][u<<1].lazy=tr[id][u<<1|1].lazy=tr[id][u].lazy; tr[id][u].lazy=-1; } void build(int id,int u,int l,int r){ if(l==r){ tr[id][u]={l,r,0,-1}; return; } tr[id][u]={l,r,0,-1}; int mid=(l+r)>>1; build(id,u<<1,l,mid); build(id,u<<1|1,mid+1,r); push_up(id,u); } void update(int id,int u,int l,int r,int v){ //1表示合法的单位,每次更新合法的点 if(tr[id][u].l>=l && tr[id][u].r<=r){ tr[id][u].cnt=(tr[id][u].r-tr[id][u].l+1)*v; tr[id][u].lazy=v; return; } push_down(id,u); int mid=(tr[id][u].l+tr[id][u].r)>>1; if(l<=mid) update(id,u<<1,l,r,v); if(r>mid) update(id,u<<1|1,l,r,v); push_up(id,u); } int query(int id,int u,int l,int r){ //询问[l,r]内连续的不合法的最远位置,即第一个1出现的位置 if(!tr[id][u].cnt) return INF; if(tr[id][u].l==tr[id][u].r) return tr[id][u].l; int mid=(tr[id][u].l+tr[id][u].r)>>1; push_down(id,u); if(tr[id][u].l>=l && tr[id][u].r<=r){ if(tr[id][u<<1].cnt) return query(id,u<<1,l,mid); else return query(id,u<<1|1,mid+1,r); } int res=INF; if(l<=mid) res=query(id,u<<1,l,r); if(r>mid) res=min(res,query(id,u<<1|1,l,r)); return res; } int main(){ ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); int _; cin>>_; while(_--){ cin>>n>>m>>k; rep(i,1,n) col[i].clear(); rep(i,1,k){ int x,y; cin>>x>>y; col[x].pb(y); } build(0,1,1,m); build(1,1,1,m); update(0,1,1,1,1); ll ans=0; rep(i,1,n){ sort(col[i].begin(),col[i].end()); int l=0; for(auto to:col[i]){ if(l+1<=to-1){ int pos=query((i&1)^1,1,l+1,to-1); if(pos!=INF) update(i&1,1,pos,to-1,1); } l=to; } if(l+1<=m){ int pos=query((i&1)^1,1,l+1,m); if(pos!=INF) update(i&1,1,pos,m,1); } ans+=tr[i&1][1].cnt; update((i&1)^1,1,1,m,0); //上一行全部改为不合法,当作下一行用 } cout<<ans<<'\n'; } return 0; }
𝓐𝓬𝓱𝓲𝓮𝓿𝓮𝓶𝓮𝓷𝓽 𝓹𝓻𝓸𝓿𝓲𝓭𝓮𝓼 𝓽𝓱𝓮 𝓸𝓷𝓵𝔂 𝓻𝓮𝓪𝓵
𝓹𝓵𝓮𝓪𝓼𝓾𝓻𝓮 𝓲𝓷 𝓵𝓲𝓯𝓮