淺談React雙向資料繫結原理
阿新 • • 發佈:2021-11-15
題目
一個長度為\(n\)的串,有\(m\)個限制條件,\(l_1,r_1,l_2,r_2(r_1-l_1=r_2-l_2)\)表示,字串\([l_1,r_1]\)和字串\(l_2,r_2\)相等.你可以在除最高位的每一位填0123456789
,最高位不能為0
,問方案.
\(n,m\le 10^5\)
思路
容易將問題轉化為求字串中不同的字元數量.
用並查集維護,用類似st表的方式優化.
我們設字串中起始位置為\(i\),長度為\(2^j\)的字串編號為\(st_{i,j}\).它所在的集合為\(fa_{st_{i,j}}\).在同一個集合的字串相等.
對於限制條件,我們可以二進位制拆分原來的字串,在並查集上維護.
處理完限制條件後,我們需要將相等關係下傳,得到長度為1
的字串的相等關係,從而解決這道題.
具體地說我們列舉一個以\(i\)為起點,長度為\(2^j\)的字串,把它分成兩半:起點為\(i\),長度為\(2^{j-1}\),以及起點為\(i+2^{j-1}\),長度為\(2^{j-1}\).我們在並查集中找到原串的相同串,設它的起始位置為\(id\),(這一步可能需要一個額外的陣列維護),也將它分為兩半,起點為\(id\),長度為\(2^{j-1}\),以及起點為\(id+2^{j-1}\),長度為\(2^{j-1}\).
可以得到兩組相同串:起點為\(i\),長度為\(2^{j-1}\)的串和起點為\(id\)
程式碼
#include <iostream> #include <cstdio> #include <unordered_set> using namespace std; int read() { int re = 0; char c = getchar(); bool negt = false; while(c < '0' || c > '9')negt |= (c == '-') , c = getchar(); while(c >= '0' && c <= '9')re = (re << 1) + (re << 3) + c - '0' , c = getchar(); return negt ? -re : re; } const int N = 1e5 + 10 , logN = 20; struct DSU { int fa[N * logN]; void init(int n) { for(int i = 1 ; i <= n ; i++) fa[i] = i; } int findroot(int x) { return fa[x] == x ? x : (fa[x] = findroot(fa[x])); } void merge(int x , int y) { if(findroot(x) != findroot(y)) fa[findroot(x)] = findroot(y); } } dsu; int n , m; int st[N][logN]; int indx[N * logN];//編號為i的串,起始位置為indx[i]. int log2[N]; unordered_set<int> s; void init() { int cnt = 0;//編號 for(int j = 0 ; (1 << j) <= n ; j++) for(int i = 1 ; i + (1 << j) - 1 <= n ; i++) st[i][j] = ++cnt , indx[cnt] = i; for(int i = 2 ; i <= n ; i++) log2[i] = log2[i - 1] + ((i & i - 1) == 0); dsu.init(cnt); } typedef long long ll; ll mod = 1e9 + 7; int poww(ll mul , int p) { int ans = 1; for( ; p ; p >>= 1)ans = (ans * ((p & 1) ? mul : 1)) % mod , mul = mul * mul % mod; return ans; } int main() { n = read() , m = read(); init(); for(int i = 1 ; i <= m ; i++) { int l1 = read() , r1 = read() , l2 = read() , r2 = read(); int len = r1 - l1 + 1; int p = l1 , q = l2; for(int j = log2[len] ; j >= 0 ; j--) { if(p + (1 << j) - 1 > r1)continue; dsu.merge(st[p][j] , st[q][j]); p += (1 << j) , q += (1 << j); } } for(int j = log2[n] + 1 ; j > 0 ; j--) { for(int i = 1 ; i + (1 << j) - 1 <= n ; i++) { int id = indx[dsu.findroot(st[i][j])]; dsu.merge(st[i][j - 1] , st[id][j - 1]); dsu.merge(st[i + (1 << j - 1)][j - 1] , st[id + (1 << j - 1)][j - 1]); } } for(int i = 1 ; i <= n ; i++) s.insert(dsu.findroot(i)); printf("%lld" , 9ll * poww(10 , s.size() - 1) % mod); // cout << s.size(); return 0; }