题意
思路
思路很巧妙,首先是枚举每个值的贡献,然后找到了规律,下次做题的时候线分析每个题有啥好规律,然后根据规律做题。
再就是线段树的这个思路,感觉很巧妙,通过设置每一段的值,假设这一段出现过,那值就不是0,可以更新一次,否则,就是没出现过,值就是0。
代码
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
# define int long long
const int N=3e5+10;
const int mod=998244353;
struct node {
int l,r;
int maxn;
int lazy;
}tr[N*4];
void build(int u,int l,int r){
tr[u]={l,r,0,0};
if(tr[u].l==tr[u].r) return;
int mid=tr[u].l+tr[u].r>>1;
build(u<<1,l,mid);
build(u<<1|1,mid+1,r);
}
void modify(int u,int l,int r,int val){
if(tr[u].l>=l && tr[u].r<=r){
tr[u].maxn=val;
return;
}
int mid=tr[u].l+tr[u].r>>1;
if(l<=mid) modify(u<<1,l,r,val);
if(r>mid) modify(u<<1|1,l,r,val);
}
void query(int u,int l ,int &val){//val这里传地址,函数就不用返回最大值了
val=max(val,tr[u].maxn);
//如果没有包含这个l值,结果都是0,只有包含的才不是
if(tr[u].r==tr[u].l) return ;
int mid=tr[u].l+tr[u].r>>1;
if(l<=mid) query(u<<1,l,val);
if(l>mid) query(u<<1|1,l,val);
}
int qmi(int a,int b){
int ans =1;
while(b){
if(b&1) ans=ans*a%mod;
b>>=1;
a=a*a%mod;
}
return ans;
}
signed main()
{
build(1,0,300000);
int n;cin>>n;
for(int i=1;i<=n;i++){
int l,r;
cin>>l>>r;
modify(1,l,r,i);
}
// cout<<"fs"<<endl;
int ans=0;
for(int i=0;i<=300000;i++){
int val=0,sum=0;
query(1,i,val);
if(val==0) continue;//没有出现这个值
if(val==1){//在第1段出现了,后面有n-1个符号
sum=qmi(2,n-1);
}
else{//后面有n-val个符号,前面有3^(val-2)个集合
sum=qmi(2,n-val+1)*qmi(3,val-2)%mod;
sum%=mod;
}
ans+=sum;
ans%=mod;
}
cout<<ans<<endl;
return 0;
}
标签:Union,Gym,tr,int,build,lmid,Intersection,线段
From: https://www.cnblogs.com/kingwz/p/16849142.html