一、莫队
普通莫队
bool cmp(node x,node y){
return (id[x.l] != id[y.l]) ? id[x.l] < id[y.l] : x.r < y.r;
}
sort(arr+1,arr+n+1,cmp);
for (int i = 1,l = 1,r = 0;i <= n;i++){
while (l > arr[i].l) add(a[--l]);
while (r < arr[i].r) add(a[++r]);
while (l < arr[i].l) del(a[l++]);
while (r > arr[i].r) del(a[r--]);
ans[arr[i].id] = sum;
}
树上莫队
void update(int x){
vis[x] ? del(x) : add(x);
vis[x] ^= 1;
}
void dfs(int x,int fa){
in[x] = ++cnt,pos[cnt] = x;
for (int i = head[x];i;i = ed[i].nxt){
int to = ed[i].to;
if (to == fa) continue;
}
out[x] = ++cnt,pos[cnt] = x;
}
for (int i = 1;i <= m;i++){
int x = read(),y = read();
int tmp = lca(x,y);
if (in[x] > in[y]) swap(x,y);
if (x == tmp||y == tmp) arr[i].l = in[x],arr[i].r = in[y],arr[i].id = i;
else arr[i].l = out[x],arr[i].r = in[y],arr[i].id = i,arr[i].lca = tmp;
}
for (int i = 1,l = 1,r = 0;i <= n;i++){
while (l > arr[i].l) update(pos[--l]);
while (r < arr[i].r) update(pos[++r]);
while (l < arr[i].l) update(pos[l++]);
while (r > arr[i].r) update(pos[r--]);
ans[arr[i].id] = sum;
if (arr[i].lca) if (!cnt[a[arr[i].lca]]) ans[arr[i].id]]++;
}
带修莫队
for (int i = 1;i <= m;i++){
char op[5];scanf ("%s",op);
if (op[0] == 'Q') arr1[++cnt1].l = read(),arr1[cnt].r = read(),arr1[cnt1].tim = cnt2,arr1[cnt1].pos = cnt1;
else arr2[++cnt2].l = pos = read(),arr2[cnt2].val = read();
}
bool cmp(node x,node y){
if (id[x.l] != id[y.l]) return id[x.l] < id[y.l];
if (id[x.r] != id[y.r]) return id[x.r] < id[y.r];
return x.t < y.t;
}
void update(int x,int t){
if (arr1[x].l <= arr2[t].pos&&arr2[t].pos <= arr1[x].r){
del(a[arr2[t].pos]);
add(arr2[t].val);
}
swap(a[arr2[t].pos],arr2[t].val);
}
sort(arr1+1,arr1+cnt1+1,cmp);
for (int i = 1,l = 1,r = 0,t = 0;i <= cnt1;i++){
while (l > arr1[i].l) add(a[--l]);
while (r < arr1[i].r) add(a[++r]);
while (l < arr1[i].l) del(a[l++]);
while (r > arr1[i].r) del(a[r--]);
while (t < arr1[i].tim) update(i,++t);
while (t > arr1[i].tim) update(i,t--);
ans[arr1[i].pos] = sum;
}
二、Hash
双模hash,可以判断字符串是否相等
void getHash(char s1,char s2){
power1[0] = power2[0] = 1;
for (int i = 1;i < 100000;i++) power1[i] = power1[i-1]*b1 % P1,power2[i] = power2[i-1]*b2 % P2;
int len1 = strlen(s1+1),len2 = strlen(s2+1);
for (int i = 1;i <= len2;i++) sum1[i] = (sum1[i-1]*b1+s2[i]+1) % P1,sum2[i] = (sum2[i-1]*b2+s2[i]+1) % P2;
int ss1 = 0,ss2 = 0;
for (int i = 1;i <= len1;i++) (ss1 = ss1*b1+s1+1) % P1,(ss2 = ss2*b2+s2+1) % P2;
for (int i = 0;i <= len2-len1;i++){
if (ss1 % P1 == ((sum1[i+n]-sum1[i]*power1[n]) % P1+P1) % P1)
if (ss2 % P2 == ((sum2[i+n]-sum2[i]*power2[n]) % P2+P2) % P2) ……;
}
}
三、凸包
计算几何的相关概念:
向量的叉积:
1.(a(x_1,y_1) imes b(x_2,y_2) = x_1y_2-x_2y_1)
2.(|a imes b|)的值就是ab两个向量拼成的平行四边形的面积
3.(a imes b > 0)证明b在a的逆时针方向
4.(a imes b < 0)证明b在a的顺时针方向
维护凸包的时候我们就可以用叉积的性质
比如当我们维护上凸包的时候:
首先把点都按照x坐标拍好序
每次加入一个点的时候如果他和栈顶元素形成的直线在栈中最后一条直线的顺时针方向,也就是叉积 <= 0吗,证明不合法,弹出
按照这个步骤进行,最后栈中的点就是凸包上的所有点
sort(vec[x].begin(),vec[x].end(),cmpx);
int top = 0;
for (int i = 0;i < vec[x].size();i++){
node u = vec[x][i];
while (top > 1&&(u-st[top])^(st[top]-st[top-1]) <= 0) top--;
st[++top] = u;
}
一种技巧:在凸包上三分
话说可以在凸包上二分斜率,也可以直接三分索所要求得值,越靠近想要的结果的端点不变