首页 > 其他分享 >PTZ summer 2021 Day 5 D Interval

PTZ summer 2021 Day 5 D Interval

时间:2024-07-28 11:51:29浏览次数:12  
标签:rt summer node int Interval long times Day mod

记 \([l,r]\times [a,b]\) 表示区间所有的 \((x,y),x \in [l,r],y \in [a,b]\)

先考虑离散化,对每一个极小区间 \((x,y)\) 分别求解,假设有 \(n\) 给定区间包含它

若 \(n=1\),那么可以使 \([1,i_1]\times [i_1,n]\) 加上 \(1\)

如果 \(n =2\),如果按照 \(n=1\) 的做法会重复计算,那么可以使 \([1,i_1]\times [i_2,n]\) 减去 \(1\),那么 \(n>2\) 同理,可以看作有 \(n\) 个点的链,那么点数减去边数恰好为 \(1\)

可以发现一些相邻的极小区间可以合并起来,那么可以直接拿给定的区间进行操作,使用珂朵莉树维护,具体来说编号从小到大插入区间,当前应该插入 \(i\),且 \(i\) 覆盖的区间三元组为 \((l_j,r_j,id_j)\)(有些给定区间不会被完全覆盖),使 \([1,id_j]\times [i,n]\) 减去 \(r_j-l_j+1\),最后 \([1,i]\times [i,n]\) 加上区间长度即可,可以发现所有区间的加入和删除总次数为 \(\texttt{O}(n)\) 的

而 \([l,r]\times [a,b]\) 可以看作矩阵,那么扫描线加历史和维护矩阵加矩阵求和即可

具体细节看代码

#include<bits/stdc++.h>
using namespace std;
#define mid (l+r>>1)
struct node{
    int l,r,v;
    node(int l=0,int r=0,int v=0):l(l),r(r),v(v){}
    bool operator<(const node &k)const{return l<k.l;}
};
struct his{
    long long h,v,a,b,c;
    his(long long h=0,long long v=0,long long a=0,long long b=0,long long c=0):h(h),v(v),a(a),b(b),c(c){}
}t[800001];
set <node> s;
int n,m,x,y;
long long ans[200001],w[200001];
vector <node> G[200001];
const int mod=998244353;
long long power(long long a){
    long long res=1;
    for(int b=mod-2;b;b>>=1,a=a*a%mod) if(b&1) res=res*a%mod;
    return res;
}
set <node> ::iterator split(int pos){
    auto it=s.lower_bound(node(pos,0));
    if(it!=s.end()&&(*it).l==pos) return it;
    int l=(*--it).l,r=(*it).r,v=(*it).v;
    s.erase(it);
    s.insert(node(l,pos-1,v));
    return s.insert(node(pos,r,v)).first;
}
void upd(int x,long long a,long long b,long long c,long long l){
    t[x].h=(t[x].h+t[x].v*a+l*b)%mod;
    t[x].v=(t[x].v+l*c)%mod;
    t[x].a=(t[x].a+a)%mod;
    t[x].b=(t[x].b+t[x].c*a+b)%mod;
    t[x].c=(t[x].c+c)%mod;
}
void push_down(int rt,int l,int r){
    upd(rt*2,t[rt].a,t[rt].b,t[rt].c,mid-l+1);
    upd(rt*2+1,t[rt].a,t[rt].b,t[rt].c,r-mid);
    t[rt].a=t[rt].b=t[rt].c=0;
}
void update(int rt,int l,int r,int L,int R,long long a,long long b,long long c){
    if(L<=l&&r<=R) return (void)(upd(rt,a,b,c,r-l+1));
    push_down(rt,l,r);
    if(L<=mid) update(rt*2,l,mid,L,R,a,b,c);
    if(R>mid) update(rt*2+1,mid+1,r,L,R,a,b,c);
    t[rt].h=(t[rt*2].h+t[rt*2+1].h)%mod;
    t[rt].v=(t[rt*2].v+t[rt*2+1].v)%mod;
}
long long query(int rt,int l,int r,int L,int R){
    if(L<=l&&r<=R) return t[rt].h;
    push_down(rt,l,r);
    return ((L<=mid?query(rt*2,l,mid,L,R):0)+(R>mid?query(rt*2+1,mid+1,r,L,R):0))%mod;
}
int main(){
	scanf("%d%d",&n,&m),s.insert(node(0,1e8,0));
    for(int i=1;i<=n;i++){
        scanf("%d%d",&x,&y);
        auto r=split(y),l=split(x);
        for(auto j=l;j!=r;j++) if((*j).v!=0) G[i].push_back(node((*j).v,mod-((*j).r-(*j).l+1),0));
        s.erase(l,r);
        s.insert(node(x,y-1,i));
        G[i].push_back(node(i,y-x,0));
    }
    for(int i=1;i<=m;i++){
        scanf("%d%d",&x,&y);
        w[i]=power(1ll*(y-x+1)*(y-x+2)/2%mod);
        G[y].push_back(node(x,y,i));
        G[x-1].push_back(node(x,y,-i));
    }
    for(int i=1;i<=n;i++){
        for(auto j:G[i]) if(!j.v) update(1,1,n,1,j.l,0,0,j.r);
        update(1,1,n,1,n,1,0,0);
        for(auto j:G[i]){
            if(j.v>0) ans[j.v]=(ans[j.v]+query(1,1,n,j.l,j.r))%mod;
            if(j.v<0) ans[-j.v]=(ans[-j.v]-query(1,1,n,j.l,j.r)+mod)%mod;
        }
    }
    for(int i=1;i<=m;i++) printf("%lld\n",ans[i]*w[i]%mod);
	return 0;
}

标签:rt,summer,node,int,Interval,long,times,Day,mod
From: https://www.cnblogs.com/zyxawa/p/18328049

相关文章

  • python基本语法三天速成系列day1(看完这篇你就会)
    注释注释是代码非常重要的一部分,它的主要作用有:解释代码目的:注释可以说明代码段或函数的目的和功能,帮助其他开发者快速理解代码的意图。复杂逻辑说明:对于复杂的算法或业务逻辑,通过注释可以解释这些逻辑是如何工作的,降低后续维护的难度。提高可读性:良好的注释可以使代码结......
  • 代码随想录算法训练营day25:回溯04:491.递增子序列;46.全排列
    491.递增子序列力扣题目链接(opensnewwindow)给定一个整型数组,你的任务是找到所有该数组的递增子序列,递增子序列的长度至少是2。示例:输入:[4,6,7,7]输出:[[4,6],[4,7],[4,6,7],[4,6,7,7],[6,7],[6,7,7],[7,7],[4,7,7]]说明:给定数组的长度不......
  • P10463 Interval GCD
    P10463IntervalGCD原题传送门思路首先,有个性质:对于任意多整数,它们的最大公约数与它们的差分序列的最大公约数相同,可以通过以下证明。\(\foralla,b,c\in\mathbb{N}\text{,有}\gcd(a,b,c)=\gcd(a,b-a,c-b)\)\(\text{证明:设}d\mida,d\midb,d\midc\)......
  • 代码随想录 day 37 完全背包 | 零钱兑换 II | 组合总和 Ⅳ | 爬楼梯 (进阶)
    完全背包完全背包解题思路由于我们可以重复放入物体,那么在遍历背包重量时就必须从前往后遍历,因为这样就可以重复放入了,其余的部分和01背包相同知识点完全背包心得学会了如何解决纯完全背白零钱兑换II零钱兑换II解题思路和之前01背包求总数的思路相同,唯一的不同点在......
  • MATLAB学习日志DAY20
     结构体(1)结构体是多维MATLAB数组,包含可按文本字段标志符访问的元素。例如,S.name='EdPlum';S.score=83;S.grade='B+'创建一个具有三个字段的标量结构体:S=name:'EdPlum'score:83grade:'B+'与MATLAB环境中的所有其他内容一样,结构体......
  • SMU Summer 2024 Contest Round 8
    SMUSummer2024ContestRound8Product思路注意到\(\prod\limits_{i=1}^NL_i\le10^5\),也就是说N不会超过16,因为\(2^{17}>10^5\),所以我们可以直接暴搜。代码#include<bits/stdc++.h>usingnamespacestd;usingi64=longlong;intmain(){ios::sync_with......
  • 入门C语言Day18——break&continue&goto语句
    前面的博文中有提到do-while与for循环语句,其中的流程图中有break和continue这两个部分还没解释。所以今天先来解释一下break与continue语句。break和continue两个关键字都被运用在循环中。break的作用是永久的终止循环,只要break被执行,直接就会跳出循环,继续往后执行。......
  • 从零开始的JAVAday22~day28
    上周我们学习了如何定义变量,这周我们学习如何给变量起名。硬性要求:1.由数字、字母、下划线()和美元符($)组成2.不能以数字开头3.不能是关键字4.区分大小写软性要求:小驼峰命名法:存在一个单词时所有字母都小写,存在多个字母时第一个单词小写第二个单词首字母大写大驼峰命名法......
  • 代码随想录||day25 非递减子序列,全排列问题
    491非递减子序列力扣题目链接题目描述:给你一个整数数组 nums ,找出并返回所有该数组中不同的递增子序列,递增子序列中 至少有两个元素 。你可以按 任意顺序 返回答案。数组中可能含有重复元素,如出现两个整数相等,也可以视作递增序列的一种特殊情况。示例1:输入:nums=......
  • 代码随想录day24打卡|| 93复原ip地址 78子集| 90子集||
    93复原ip地址力扣题目链接题目描述有效IP地址 正好由四个整数(每个整数位于 0 到 255 之间组成,且不能含有前导 0),整数之间用 '.' 分隔。例如:"0.1.2.201" 和"192.168.1.1" 是 有效 IP地址,但是 "0.011.255.245"、"192.168.1.312" 和 "[email protected]" 是 无......