写不出线段树。用了其他方法。把 pirate 压缩进一个 sqrt(N) X sqrt(N) 的表,每一行增加一些额外信息,然后可以使得各种操作的时间复杂度都是 O(sqrt(N))。写了好久,代码好长,比赛时写不出这种题目。 #include <cstdio> #include <cstdlib> #include <cassert> #include <cmath> #include <algorithm> #include <vector> using namespace std; // #undef _DEBUG enum Pirate { PIR_BUC, PIR_BAR }; enum Op { OP_INV, OP_BUC, OP_BAR, OP_NIL }; struct Table { vector <vector <Pirate> > data; // pirates matrix vector <int> buc; // number of Buccaneer vector <Op> op; // unapplied operation of a row int root; // table size int pirates; // number of pirates #ifdef _DEBUG void PrintAllDatas() { printf("/n buc, op, data:/n"); for(int i=0; i<data.size(); ++i) { char strOp[10]; if(op[i] == OP_NIL) sprintf(strOp, "nil"); else if(op[i] == OP_BUC) sprintf(strOp, "buc"); else if(op[i] == OP_BAR) sprintf(strOp, "bar"); else sprintf(strOp, "inv"); printf("%5d%5s ", buc[i], strOp); for(int k=0; k<data[i].size(); ++k) printf(data[i][k] == PIR_BUC ? " 1" : " 0"); printf("/n"); } } #endif // initilaizer, O(N) void Init(const vector <Pirate> &p) { #ifdef _DEBUG printf("Init()/n"); #endif pirates = p.size(); double r = sqrt(double(p.size())); root = int(ceil(r) + 0.5); assert(root * root >= p.size()); assert((root - 1) * (root - 1) < p.size()); data.resize(root); fill(data.begin(), data.end(), vector <Pirate> ()); op.resize(root); fill(op.begin(), op.end(), OP_NIL); buc.resize(root); fill(buc.begin(), buc.end(), 0); for(int i=0; i<p.size(); ++i) data[i / root].push_back(p[i]); for(int i=0; i<root; ++i) { for(int k=0; k<data[i].size(); ++k) { if(data[i][k] == PIR_BUC) ++buc[i]; } } } // a new operation applied to a row, O(1) void NewOp(int row, Op newOp) { if(row >= root) return; #ifdef _DEBUG printf("NewOp()/n"); #endif Op &oldOp = op[row]; switch(newOp) { case OP_BUC: case OP_BAR: oldOp = newOp; break; case OP_INV: if(oldOp == OP_BAR) oldOp = OP_BUC; else if(oldOp == OP_BUC) oldOp = OP_BAR; else if(oldOp == OP_INV) oldOp = OP_NIL; else assert(oldOp == OP_NIL), oldOp = OP_INV; break; default: assert(false); } } // make all pirates in a row into Buccaneer, O(sqrt(N)) void Buc(int row) { if(row >= root) return; #ifdef _DEBUG printf("Buc(%d)/n", row); #endif for(int i=0; i<data[row].size(); ++i) data[row][i] = PIR_BUC; buc[row] = data[row].size(); } // make all pirates in a row into Barbary, O(sqrt(N)) void Bar(int row) { if(row >= root) return; #ifdef _DEBUG printf("Bar(%d)/n", row); #endif for(int i=0; i<data[row].size(); ++i) data[row][i] = PIR_BAR; buc[row] = 0; } // inverse a row making all pirates in this row into opponent, O(sqrt(N)) void Inv(int row) { if(row >= root) return; #ifdef _DEBUG printf("Inv(%d)/n", row); #endif for(int i=0; i<data[row].size(); ++i) data[row][i] = (data[row][i] == PIR_BUC ? PIR_BAR : PIR_BUC); buc[row] = data[row].size() - buc[row]; } // process a operation of a row, O(sqrt(N)) void ProcessOp(int row) { if(row >= root) return; #ifdef _DEBUG printf("ProcessOp(%d)/n", row); #endif switch(op[row]) { case OP_BAR: Bar(row); break; case OP_BUC: Buc(row); break; case OP_INV: Inv(row); break; default: assert(op[row] == OP_NIL); break; } op[row] = OP_NIL; } // make pirates between index a, b in a row into Barbary, O(sqrt(N)) void Bar(int row, int a, int b) // [a, b) { if(row >= root) return; #ifdef _DEBUG printf("Bar(%d, %d, %d)/n", row, a, b); #endif assert(b <= data[row].size()); for(int i=a; i<b; ++i) { if(data[row][i] != PIR_BAR) --buc[row]; data[row][i] = PIR_BAR; } } // make pirates between index a, b in a row into Buccaneer, O(sqrt(N)) void Buc(int row, int a, int b) // [a, b) { if(row >= root) return; #ifdef _DEBUG printf("Buc(%d, %d, %d)/n", row, a, b); #endif assert(b <= data[row].size()); for(int i=a; i<b; ++i) { if(data[row][i] != PIR_BUC) ++buc[row]; data[row][i] = PIR_BUC; } } // inverse pirates between index a, b in a row, O(sqrt(N)) void Inv(int row, int a, int b) // [a, b) { if(row >= root) return; #ifdef _DEBUG printf("Inv(%d, %d, %d)/n", row, a, b); #endif assert(b <= data[row].size()); for(int i=a; i<b; ++i) { if(data[row][i] == PIR_BUC) { data[row][i] = PIR_BAR; --buc[row]; } else { assert(data[row][i] == PIR_BAR); data[row][i] = PIR_BUC; ++buc[row]; } } } // make all pirates between index a, b of the original array into Buccaneer, O(sqrt(N)) void Buc(int a, int b) // [a, b) { #ifdef _DEBUG printf("Buc(%d, %d)/n", a, b); #endif int sr = a / root + 1; int er = b / root; for(int i=sr; i<er; ++i) NewOp(i, OP_BUC); ProcessOp(a / root); ProcessOp(b / root); if(sr <= er) { Buc(sr - 1, a % root, root); Buc(er, 0, b % root); } else { Buc(sr - 1, a % root, b % root); } #ifdef _DEBUG PrintAllDatas(); #endif } // make all pirates between index a, b of the original array into Barbary, O(sqrt(N)) void Bar(int a, int b) // [a, b) { #ifdef _DEBUG printf("Bar(%d, %d)/n", a, b); #endif int sr = a / root + 1; int er = b / root; for(int i=sr; i<er; ++i) NewOp(i, OP_BAR); ProcessOp(a / root); ProcessOp(b / root); if(sr <= er) { Bar(sr - 1, a % root, root); Bar(er, 0, b % root); } else { Bar(sr - 1, a % root, b % root); } #ifdef _DEBUG PrintAllDatas(); #endif } // inverse pirates between index a, b of the original array, O(sqrt(N)) void Inv(int a, int b) // [a, b) { #ifdef _DEBUG printf("Inv(2)/n"); #endif int sr = a / root + 1; int er = b / root; for(int i=sr; i<er; ++i) NewOp(i, OP_INV); ProcessOp(a / root); ProcessOp(b / root); if(sr <= er) { Inv(sr - 1, a % root, root); Inv(er, 0, b % root); } else { Inv(sr - 1, a % root, b % root); } #ifdef _DEBUG PrintAllDatas(); #endif } // get the number of Buccaneer between index a, b in a row, O(sqrt(N)) int GetBuc(int row, int a, int b) // [a, b) { if(row >= root) return 0; #ifdef _DEBUG printf("GetBuc(%d, %d, %d)/n", row, a, b); #endif assert(op[row] == OP_NIL); int ret = 0; for(int i=a; i<b; ++i) { if(data[row][i] == PIR_BUC) ++ret; } return ret; } // get the number of Buccaneer between index a, b of the original array, O(sqrt(N)) int GetBuc(int a, int b) // [a, b) { #ifdef _DEBUG printf("GetBuc(%d, %d)/n", a, b); #endif int ret = 0; int sr = a / root + 1; int er = b / root; for(int i=sr; i<er; ++i) { switch(op[i]) { case OP_INV: ret += data[i].size() - buc[i]; break; case OP_BAR: ret += 0; break; case OP_BUC: ret += data[i].size(); break; default: assert(op[i] == OP_NIL); ret += buc[i]; break; } } ProcessOp(a / root); ProcessOp(b / root); if(sr <= er) ret += GetBuc(sr - 1, a % root, root) + GetBuc(er, 0, b % root); else ret += GetBuc(sr - 1, a % root, b % root); #ifdef _DEBUG PrintAllDatas(); #endif return ret; } }; int main() { int cs; scanf("%d", &cs); Table tb; for(int i=0; i<cs; ++i) { int segs, n; scanf("%d", &segs); vector <Pirate> pirate; for(int k=0; k<segs; ++k) { char buf[100]; scanf("%d%s", &n, buf); for(int d=0; d<n; ++d) { char *p = buf; while(*p) pirate.push_back(*p++ == '1' ? PIR_BUC : PIR_BAR); } } tb.Init(pirate); printf("Case %d:/n", i + 1); int t = 1; int q; scanf("%d", &q); for(int k=0; k<q; ++k) { char cmd[100]; int a, b; scanf("%s%d%d", cmd, &a, &b); switch(*cmd) { case 'F': tb.Buc(a, b + 1); break; case 'E': tb.Bar(a, b + 1); break; case 'I': tb.Inv(a, b + 1); break; default: assert(*cmd == 'S'); printf("Q%d: %d/n", t++, tb.GetBuc(a, b + 1)); break; } } } return 0; }