問題の意味
N二乗\((N \のLeq 1E5)\) 、ゼロの各グリッド初期重み値。1.各時間:これは、2つの操作をサポート\([L、R] \ ) の合計を、1重量値、それは最初のiに追加された場合、すべてのグリッドでは、グリッドのために、アイテムIを添加し、さもなければ重み時間;. 2加算間隔
種類、次数nを有する物品
考え
アカウントにアイテムの多くのカテゴリを取って、その数はまだ範囲の1E5のレベルを操作しているので、あなたは維持するために、動的なデータ構造を使用することができますが
1.set +セグメントツリー
試験の練習
最初のアイデアは、それぞれが全1色を維持するために、間隔を設定し、セットの愚か数や種類など多くのオープンなので、質問が早くなり、追加する範囲を見つけるといくつかの重複部分のセクションを持っているとなり残りの部分に1を加算し、2部分に重なります。
同様に、会場の予約、重複セクションのすべては、我々は、それらを削除し、操作を変更するには、検索操作を直接見ることができ、かつ間隔がに追加しますマージ、その後、それらをセットに参加するために、ブロックセクションとして加えました。一度横断する部分が削除されますので、アルゴリズムの時間複雑であるので、()O(nlog ^ 2nの\ \)
コード
#include<bits/stdc++.h>
#define N 200005
#define Min(x,y) ((x)<(y)?(x):(y))
#define Max(x,y) ((x)>(y)?(x):(y))
#define IT set<SXK>::iterator
using namespace std;
typedef long long ll;
const ll mod = 998244353;
int n,q;
ll sum[N<<2],sign_mul[N<<2],sign_add[N<<2];
struct SXK
{
int l,r;
SXK(int ll=0,int rr=0) {l=ll;r=rr;}
bool operator < (const SXK a)const
{
return r < a.l;
}
};//保证同颜色的区间不重叠
set<SXK> col[N];
template <class T>
void read(T &x)
{
char c;int sign=1;
while((c=getchar())>'9'||c<'0') if(c=='-') sign=-1; x=c-48;
while((c=getchar())>='0'&&c<='9') x=x*10+c-48; x*=sign;
}
void add_sign_add(int rt,int l,int r,ll val)
{
sign_add[rt]=(sign_add[rt]+val)%mod;
sum[rt]=(sum[rt]+(r-l+1)*val%mod)%mod;
}
void add_sign_mul(int rt,int l,int r,ll val)
{
sign_add[rt]=sign_add[rt]*val%mod;
sign_mul[rt]=sign_mul[rt]*val%mod;
sum[rt]=sum[rt]*val%mod;
}
void pushdown(int rt,int l,int r)
{
if(sign_mul[rt]==1&&sign_add[rt]==0) return;
int mid=(l+r)>>1;
add_sign_mul(rt<<1,l,mid,sign_mul[rt]);
add_sign_add(rt<<1,l,mid,sign_add[rt]);
add_sign_mul(rt<<1|1,mid+1,r,sign_mul[rt]);
add_sign_add(rt<<1|1,mid+1,r,sign_add[rt]);
sign_mul[rt]=1;
sign_add[rt]=0;
}
void modify_add(int rt,int l,int r,int x,int y)
{
if(x>y) return;
if(x<=l&&r<=y) return add_sign_add(rt,l,r,1);
int mid=(l+r)>>1;
pushdown(rt,l,r);
if(x<=mid) modify_add(rt<<1,l,mid,x,y);
if(y>mid) modify_add(rt<<1|1,mid+1,r,x,y);
sum[rt]=(sum[rt<<1]+sum[rt<<1|1])%mod;
}
void modify_mul(int rt,int l,int r,int x,int y)
{
if(x>y) return;
if(x<=l&&r<=y) return add_sign_mul(rt,l,r,2);
int mid=(l+r)>>1;
pushdown(rt,l,r);
if(x<=mid) modify_mul(rt<<1,l,mid,x,y);
if(y>mid) modify_mul(rt<<1|1,mid+1,r,x,y);
sum[rt]=(sum[rt<<1]+sum[rt<<1|1])%mod;
}
ll query(int rt,int l,int r,int x,int y)
{
if(x<=l&&r<=y) return sum[rt];
int mid=(l+r)>>1;
pushdown(rt,l,r);
ll ret=0;
if(x<=mid) ret+=query(rt<<1,l,mid,x,y);
if(y>mid) ret+=query(rt<<1|1,mid+1,r,x,y);
return ret%mod;
}
int main()
{
freopen("multiset.in","r",stdin);
freopen("multiset.out","w",stdout);
read(n);read(q);
for(int i=0,t=N-1;i<=t;++i) sign_mul[i]=1;
while(q--)
{
int opt,l,r,x;
read(opt);read(l);read(r);
if(opt==1)
{
read(x);//向[l,r]加入x
int L=l,R=r;
int dl=l;//dl表示现在应该处理的最左边
IT it=col[x].find(SXK(l,r));//找到第一个有交集的区间
while( it!=col[x].end() )
{
modify_add(1,1,n,dl,it->l - 1);
modify_mul(1,1,n,Max(it->l,dl),Min(it->r,r));
dl=it->r+1;
L=Min(L,it->l);
R=Max(R,it->r);
col[x].erase(it);
it=col[x].find(SXK(l,r));
}
modify_add(1,1,n,dl,r);//处理最后一段
////这一段可以有更简单的写法,时间差不多
col[x].insert(SXK(L,R));
}
else printf("%lld\n",query(1,1,n,l,r));
}
return 0;
}
2.動的な処方セグメントツリー
明らかに、セグメントツリーの色の爆発の理由は無駄なスペースがたくさん開かれ、直接の動的な最適化は、(処方箋セグメントツリーことができますだから、簡単な)