[牛客] [# 1108 E] Grid
2019牛客国庆集训派对day3
链接:https://ac.nowcoder.com/acm/contest/1108/E
来源:牛客网
题意
在一个$10 ^ 9 * 10 ^ 9$ 的方格中,每次把$[l, r]$的每一行整行连通(行间没关系),或者把$[l, r]$列连通,输出连通块的个数,操作为$10 ^ 5$ 次。
思路
本题有个重要的特性,只要有一个行连通和列连通的操作后,之后的连通块就两种情况,一是各个单独成块的小格子,还有就是一个大连通块。
我:先离散化,对行和列各搞了一个线段树,每次修改看影响了多少个单独的格子,在上次的答案中去掉即可,然后在线段树中标记去掉的列或行。
// #pragma GCC optimize(2) // #pragma GCC optimize(3) // #pragma GCC optimize(4) #include <algorithm> #include <iterator> #include <iostream> #include <cstring> #include <cstdlib> #include <iomanip> #include <bitset> #include <cctype> #include <cstdio> #include <string> #include <vector> #include <stack> #include <cmath> #include <queue> #include <list> #include <map> #include <set> #include <cassert> //#include <unordered_set> //#include <unordered_map> // #include<bits/extc++.h> // using namespace __gnu_pbds; using namespace std; #define pb push_back #define fi first #define se second #define debug(x) cerr<<#x << " := " << x << endl; #define bug cerr<<"-----------------------"<<endl; #define FOR(a, b, c) for(int a = b; a <= c; ++ a) typedef long long ll; typedef long double ld; typedef pair<int, int> pii; typedef pair<ll, ll> pll; const int inf = 0x3f3f3f3f; const ll inff = 0x3f3f3f3f3f3f3f3f; const int mod = 1e9+7; template<typename T> inline T read(T&x){ x=0;int f=0;char ch=getchar(); while (ch<'0'||ch>'9') f|=(ch=='-'),ch=getchar(); while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); return x=f?-x:x; } /**********showtime************/ const int maxn = 1e5+9; struct Q{ int tp; int a, b; } qu[maxn]; struct Tree{ vector<int>vec; int getid(int x) { return lower_bound(vec.begin(), vec.end(), x) - vec.begin() + 1; } int N; void init(int n) { vec.pb(1); vec.pb(n+1); sort(vec.begin(), vec.end()); vec.erase(unique(vec.begin(), vec.end()), vec.end()); N = vec.size() ; } ll sum[maxn << 2]; ll lazy[maxn << 2]; void build(int le, int ri, int rt, int val) { lazy[rt] = -1; if(le == ri) { if(le < vec.size()) { sum[rt] = 1ll * (vec[le] - vec[le-1] ) * val; } else sum[rt] = 0; return; } int mid = (le + ri) >> 1; build(le, mid, rt<<1, val); build(mid+1, ri, rt<<1|1, val); sum[rt] = sum[rt<<1] + sum[rt<<1|1]; } void pushdown(int le, int ri, int rt) { lazy[rt<<1] = lazy[rt<<1|1] = lazy[rt]; sum[rt<<1] = sum[rt<<1|1] = 0; lazy[rt] = -1; } void update(int L, int R, int val, int le, int ri, int rt) { if(le >= L && ri <= R) { lazy[rt] = val; sum[rt] = 0; return; } if(lazy[rt] != -1) pushdown(le, ri, rt); int mid = (le + ri) >> 1; if(mid >= L) update(L, R, val, le, mid, rt<<1); if(mid < R) update(L, R, val, mid+1, ri, rt<<1|1); sum[rt] = sum[rt<<1] + sum[rt<<1|1]; } int query(int L, int R, int le, int ri, int rt) { if(le >= L && ri <= R) { return sum[rt]; } if(lazy[rt] != -1) pushdown(le, ri, rt); int mid = (le + ri) >> 1; int res = 0; if(mid >= L) res += query(L, R, le, mid, rt<<1); if(mid < R) res += query(L ,R, mid+1, ri, rt<<1|1); return res; } } tr[2]; int main(){ int n,m,q; while(~scanf("%d%d%d", &n, &m, &q)) { tr[0].vec.clear(); tr[1].vec.clear(); for(int i=1; i<=q; i++) { scanf("%d%d%d", &qu[i].tp, &qu[i].a, &qu[i].b); qu[i].tp --; tr[qu[i].tp].vec.pb(qu[i].a); tr[qu[i].tp].vec.pb(qu[i].b+1); } tr[0].init(n); tr[1].init(m); tr[0].build(1, tr[0].N, 1, 1); tr[1].build(1, tr[1].N, 1, 1); int pretp = -1, flag = 1; int wai = 0; ll ans = 1ll*n * m; for(int i=1; i<=q; i++) { int tp = qu[i].tp, a = qu[i].a, b = qu[i].b; if(pretp != -1 && flag && pretp != tp) { wai = 1; flag = 0; } if(tp == 0) { ll k = tr[1].sum[1]; ans -= 1ll*(tr[0].query(tr[0].getid(qu[i].a), tr[0].getid(qu[i].b + 1) - 1, 1, tr[0].N, 1)) * k; if(flag) wai += tr[0].query(tr[0].getid(qu[i].a), tr[0].getid(qu[i].b + 1) - 1, 1, tr[0].N, 1); tr[0].update(tr[0].getid(qu[i].a), tr[0].getid(qu[i].b + 1) - 1, 0, 1, tr[0].N, 1); } else { ll k = tr[0].sum[1]; ans -= 1ll*(tr[1].query(tr[1].getid(qu[i].a), tr[1].getid(qu[i].b + 1) - 1, 1, tr[1].N, 1)) * k; if(flag) wai += tr[1].query(tr[1].getid(qu[i].a), tr[1].getid(qu[i].b + 1) - 1, 1, tr[1].N, 1); tr[1].update(tr[1].getid(qu[i].a), tr[1].getid(qu[i].b + 1) - 1, 0, 1, tr[1].N, 1); } pretp = tp; printf("%lld\n", ans + wai); } } return 0; }
神人:线段树动态开点,保存有几行被连通了,有几列被连通了。每次单独计算:当行和列同时有被连通,不管形态,他们占领的格子是固定的。
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn=1e5+7; struct Tree{ int lc,rc,sum; }a[maxn*26]; int tot; int build(){ int k=++tot; a[k].lc=a[k].rc=a[k].sum=0; return k; } void insert(int p,int l,int r,int L,int R){ if(a[p].sum==r-l+1) return ; if(l>=L&&r<=R){ a[p].sum=r-l+1; return ; } int mid=(l+r)>>1; if(L<=mid){ if(!a[p].lc) a[p].lc=build(); insert(a[p].lc,l,mid,L,R); } if(R>mid){ if(!a[p].rc) a[p].rc=build(); insert(a[p].rc,mid+1,r,L,R); } a[p].sum=a[a[p].lc].sum+a[a[p].rc].sum; } int main(){ int n,m,q,rtrow,rtcal,id,l,r; ll res; while(scanf("%d%d%d",&n,&m,&q)!=EOF){ tot=0; rtrow=build(); rtcal=build(); while(q--){ scanf("%d%d%d",&id,&l,&r); if(id==1) insert(rtrow,1,n,l,r); else insert(rtcal,1,m,l,r); res=0; if(a[rtrow].sum==0) res=(m-a[rtcal].sum)*1LL*n+a[rtcal].sum; else if(a[rtcal].sum==0) res=(n-a[rtrow].sum)*1LL*m+a[rtrow].sum; else{ res=n*1LL*m-a[rtrow].sum*1LL*m-a[rtcal].sum*1LL*n+a[rtrow].sum*1LL*a[rtcal].sum+1; } printf("%lld\n",res); } } return 0; }
skr