• [CF1491H] Yuezheng Ling and Dynamic Tree


    前言

    据说这是 lxl 的题啊。

    你这分块不是也是正解吗?

    不,我这是部分分暴力。

    题目

    洛谷

    CF

    讲解

    分块就完事了。

    借用重链剖分的思想,考虑维护一个 (tp_i) 表示 (i) 跳出块外的位置。

    散块怎么改复杂度都没问题,所以我们开整块。

    对于一个整块,其大小为 (sqrt{n}),所以整块被修改了至多 (sqrt{n}) 次之后,里面的所有元素跳一次就可以出块,所以维护整块修改次数即可,超过 (sqrt{n}) 次之后就是分块版本的区间加了,很简单。

    对于询问,类似重链剖分,先跳后面的,如果它一步可以跳出块或者两个点的 (tp) 相同就暴力一步一步跳,否则跳 (tp),显然时间也是 (O(sqrt{n}))

    总时间复杂度 (O(nsqrt{n}))

    注意每次改的时候从左往右改,改散块的时候前面那个部分改了后面也要改。

    前面的 (tp) 变了,后面的 (tp) 也可能跟着变,这一点非常重要,我 ( t color{red}WA) 了很久。

    代码

    没卡常也不需要卡常的代码
    //12252024832524
    #include <cmath>
    #include <cstdio>
    #include <vector>
    #include <cstring>
    #include <algorithm>
    #define TT template<typename T>
    using namespace std;
    
    typedef long long LL;
    const int MAXN = 100010;
    int n,Q,B;
    int a[MAXN];
    
    LL Read()
    {
    	LL x = 0,f = 1; char c = getchar();
    	while(c > '9' || c < '0'){if(c == '-') f = -1;c = getchar();}
    	while(c >= '0' && c <= '9'){x = (x*10) + (c^48);c = getchar();}
    	return x * f;
    }
    TT void Put1(T x)
    {
    	if(x > 9) Put1(x/10);
    	putchar(x%10^48);
    }
    TT void Put(T x,char c = -1)
    {
    	if(x < 0) putchar('-'),x = -x;
    	Put1(x); if(c >= 0) putchar(c);
    }
    TT T Max(T x,T y){return x > y ? x : y;}
    TT T Min(T x,T y){return x < y ? x : y;}
    TT T Abs(T x){return x < 0 ? -x : x;}
    
    int tp[MAXN],cnt[MAXN],lz[MAXN];
    int ID(int x){if(x <= 1) return x-1;return (x-2)/B+1;}
    int FID(int x){return B*(x-1)+2;}
    
    int pre(int i){return Max(1,a[i]-lz[ID(i)]);}
    void up(int i)
    {
    	if(ID(pre(i))^ID(i)) tp[i] = pre(i);
    	else tp[i] = tp[pre(i)];//没出块,整个块的都tp没问题 
    }
    void solve(int l,int r,int x)//左闭右开! 
    {
    	for(int i = l;i < r;++ i)
    	{
    		a[i] = Max(a[i]-x,1);
    		up(i);
    	}
    } 
    
    int main()
    {
    	freopen("game.in","r",stdin);
    	freopen("game.out","w",stdout);
    	n = Read(); Q = Read();
    	B = ceil(sqrt(n));
    	for(int i = 2;i <= n;++ i) a[i] = Read();
    	for(int i = 2;i <= n;++ i) up(i);
    	while(Q --> 0)
    	{
    		int opt = Read(),u = Read(),v = Read();
    		if(opt == 1)
    		{
    			int U = ID(u),V = ID(v),x = Read();
    			if(U+1 >= V) solve(u,v+1,x),solve(FID(U),Min(n+1,FID(V+1)),0);//散块要改后面1
    			else
    			{
    				solve(u,FID(U+1),x);
    				for(int i = U+1;i < V;++ i)
    				{
    					++cnt[i];
    					if(cnt[i] >= B) lz[i] = Min(lz[i]+x,n);//此时tp作废 
    					else solve(FID(i),FID(i+1),x);
    				}
    				solve(FID(V),v+1,x);
    				solve(FID(V),Min(n+1,FID(V+1)),0);//散块要改后面2
    			}
    		}
    		else
    		{
    			while(u^v)
    			{
    				if(u<v) swap(u,v);
    				//一步出去  或者  在同一个块里面且出去一样
    				if((ID(pre(u))^ID(u)) || (ID(u) == ID(v) && tp[u] == tp[v])) u = pre(u);
    				else u = tp[u];//一步出不去,必定没觉醒,没觉醒之前,tp[u] 是对的 
    			}
    			Put(u,'
    ');
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    记录------敬畏生活
    不错的博客分享
    Python学习笔记(一) 字符串和编码
    OSPF(二)基础实验 ASBR--- 在OSPF中引入自治系统外部路由--- LSA4和LSA5
    OSPF(一)基本概念和基础实验
    LAMP--PHP实验(四)使用包含文件提高代码效率
    LAMP--PHP实验(三)在页面之间传送变量 及遇到问题解决
    LAMP--PHP实验(二)常量和变量
    LAMP--PHP实验(一)第一个PHP程序
    随机获取图片的API
  • 原文地址:https://www.cnblogs.com/PPLPPL/p/15398727.html
Copyright © 2020-2023  润新知