• 7.18复习笔记


    一、莫队

    普通莫队

    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;
    }
    

    一种技巧:在凸包上三分

    话说可以在凸包上二分斜率,也可以直接三分索所要求得值,越靠近想要的结果的端点不变

  • 相关阅读:
    LOJ164 高精度除法
    CQOI2013 新Nim游戏 和 BZOJ1299 巧克力棒
    UOJ514 通用测评号 和 CF891E Lust
    CF526F Pudding Monsters 和 CF997E Good Subsegments
    UOJ513 清扫银河
    SNOI2020 水池
    NOI2015 品酒大会 和 SNOI2020 字符串
    SNOI2020 生成树
    BJOI2020 封印
    UOJ523 半前缀计数
  • 原文地址:https://www.cnblogs.com/little-uu/p/15030952.html
Copyright © 2020-2023  润新知