題意概要:一條直線上有 \(n+1\) 個點和 \(n\) 條道路,每條道路連通相鄰兩個點。在 \(q\) 個時刻內,每一個時刻有以下兩種操做之一:c++
\(n,q\leq 3\times 10^5\),時限 \(5s\)git
切了前兩題讓我還覺得今年apio能ak的說,這題沒切主要是由於沒有想到能夠將若干段區間的和變爲全部右端點的座標減去全部左端點的座標,以前一直在想如何計算修改對答案的貢獻來着api
在這題裏,鏈接即一段存在區間的左端點,減去當前時刻 \(t\),斷開即一段區間的右端點,加上當前時刻 \(t\)。特別的,當一次詢問時若他們之間連通,則須要再次強行加上當前時刻 \(t\)。spa
考慮切換道路 \((x,x+1)\),找到 \(x\) 往左走的最遠端 \(l\),與 \(x+1\) 往右走的最遠端 \(r\),則此次切換的影響爲:左端點在 \([l,x]\) 內,且右端點在 \([x+1,r]\) 內的全部區間。code
放到平面上去就是一個矩形,而詢問就是詢問這個平面上的一個點。有時間、\(x\)、\(y\)共三維,用 \(CDQ+BIT\) 可作到 \(O(n\log^2n)\)。get
至於找到每一個位置向左向右的最遠點,用 \(set\) 維護一下全部的極長道路區間便可it
//loj-3146 #include <bits/stdc++.h> using namespace std; #define lb(x) (x&(-x)) template <typename _tp> inline void read(_tp&x) { char ch=getchar();x=0;while(!isdigit(ch))ch=getchar(); while(isdigit(ch))x=x*10+ch-'0',ch=getchar(); } const int N = 301000; int n; namespace WK { namespace BIT { int d[N]; inline void add(int x, int v) {for(;x<=n;x+=lb(x)) d[x] += v;} inline int qry(int x) {int r=0;for(;x;x^=lb(x))r+=d[x];return r;} } struct node { int op, x, y, v; } q[N*4], b[N*4]; int Ans[N], Qs, tot; void qwq(int l, int r) { if(l == r) return ; int m = l + r >> 1; qwq(l, m), qwq(m+1, r); int t0 = l, t1 = m + 1; int tt = l; while(t0 <= m or t1 <= r) { if((t0 <= m and t1 <= r and q[t0].x <= q[t1].x) or t1 > r) { if(q[t0].op == 0) BIT::add(q[t0].y, q[t0].v); b[tt++] = q[t0++]; } else { if(q[t1].op == 1) Ans[q[t1].v] += BIT::qry(q[t1].y); b[tt++] = q[t1++]; } } for(int i=l;i<=m;++i) if(q[i].op == 0) BIT::add(q[i].y, -q[i].v); for(int i=l;i<=r;++i) q[i] = b[i]; } void work() { qwq(1, tot); for(int i=1;i<=Qs;++i) printf("%d\n", Ans[i]); } inline void add_modify(int x0, int x1, int y0, int y1, int v) { q[++tot] = (node) {0, x0, y0, +v}; q[++tot] = (node) {0, x0, y1+1, -v}; q[++tot] = (node) {0, x1+1, y0, -v}; q[++tot] = (node) {0, x1+1, y1+1, +v}; } inline void add_query(int x, int y, int vl) { q[++tot] = (node) {1, x, y, ++Qs}; Ans[Qs] = vl; } } char str[N]; bool st[N]; int Q; typedef pair<int,int> pii; set <pii> c; set <pii> :: iterator it, itr; #define ins insert #define ers erase namespace BIT { int d[N]; inline void add(int x, int v) {for(;x<=n;x+=lb(x)) d[x] += v;} inline int qry(int l, int r) { int res = 0; for(;l;l^=lb(l)) res -= d[l]; for(;r;r^=lb(r)) res += d[r]; return res; } } int main() { read(n), read(Q); scanf("%s", str+1); str[++n] = '0'; for(int i=1;i<=n;++i) { st[i] = str[i] == '1'; if(st[i]) BIT::add(i+1, +1); } for(int i=1,j;(j=i)<=n;i=j+1) { while(j < n and st[j]) ++j; c.ins(pii(i, j)); } char opt[7]; int x, y; for(int i=1;i<=Q;++i) { scanf("%s", opt); if(opt[0] == 't') { read(x); if(st[x]) { itr = c.upper_bound(pii(x, n+1)), --itr; int l = itr->first, r = itr->second; WK::add_modify(l, x, x+1, r, +i); c.ers(itr), c.ins(pii(l, x)), c.ins(pii(x+1, r)); BIT::add(x+1, -1); st[x] = false; } else { it = itr = c.upper_bound(pii(x, n+1)), --it; int l = it->first, r = itr->second; WK::add_modify(l, x, x+1, r, -i); c.ers(it), c.ers(itr), c.ins(pii(l, r)); BIT::add(x+1, +1); st[x] = true; } } else { read(x), read(y); WK::add_query(x, y, BIT::qry(x, y) == y-x ? +i : 0); } } WK::work(); return 0; }