8.数据结构

数据结构

开题顺序: \(WHABCEIG\)

\(A\) CF2042D Recommendations

  • 扫描线维护 \(\le l\) 的最大值和 \(\ge r\) 的最小值。

    点击查看代码
    int l[200010],r[200010],d[200010],st[200010],ed[200010];
    vector<pair<int,int> >q[200010];
    multiset<int>s;
    multiset<int>::iterator it;
    void slove1(int n)
    {
    	s.clear();
    	for(int i=1;i<=n;i++)  
    	{
    		q[i].clear();
    		d[i]=r[i];
    	}
    	sort(d+1,d+1+n);
    	d[0]=unique(d+1,d+1+n)-(d+1);
    	for(int i=1;i<=n;i++)  q[lower_bound(d+1,d+1+d[0],r[i])-d].push_back(make_pair(l[i],i));
    	for(int i=d[0];i>=1;i--)
    	{
    		sort(q[i].begin(),q[i].end());
    		for(int j=0;j<q[i].size();j++)  s.insert(q[i][j].first);
    		for(int j=0;j<q[i].size();j++)
    		{
    			s.erase(s.find(q[i][j].first));
    			it=s.upper_bound(q[i][j].first);
    			if(it!=s.begin()&&s.empty()==0)  st[q[i][j].second]=*prev(it);
    			s.insert(q[i][j].first);
    		}
    	}
    }
    void slove2(int n)
    {
    	s.clear();
    	for(int i=1;i<=n;i++)  
    	{
    		q[i].clear();
    		d[i]=l[i];
    	}
    	sort(d+1,d+1+n);
    	d[0]=unique(d+1,d+1+n)-(d+1);
    	for(int i=1;i<=n;i++)  q[lower_bound(d+1,d+1+d[0],l[i])-d].push_back(make_pair(r[i],i));
    	for(int i=1;i<=d[0];i++)
    	{
    		sort(q[i].begin(),q[i].end(),greater<pair<int,int> >());
    		for(int j=0;j<q[i].size();j++)  s.insert(q[i][j].first);
    		for(int j=0;j<q[i].size();j++)
    		{
    			s.erase(s.find(q[i][j].first));
    			it=s.lower_bound(q[i][j].first);
    			if(it!=s.end()&&s.empty()==0)  ed[q[i][j].second]=*it;
    			s.insert(q[i][j].first);
    		}
    	}
    }
    int main()
    {
    // #define Isaac
    #ifdef Isaac
    	freopen("in.in","r",stdin);
    	freopen("out.out","w",stdout);
    #endif
    	int t,n,i,j;
    	cin>>t;
    	for(j=1;j<=t;j++)
    	{
    		cin>>n;
    		for(i=1;i<=n;i++)  st[i]=ed[i]=0x3f3f3f3f;
    		for(i=1;i<=n;i++)  cin>>l[i]>>r[i];
    		slove1(n);  slove2(n);
    		for(i=1;i<=n;i++)  cout<<(st[i]!=0x3f3f3f3f&&ed[i]!=0x3f3f3f3f)*((ed[i]-st[i]+1)-(r[i]-l[i]+1))<<endl;
    	}
    	return 0;
    }
    

\(B\) HDU5603 the soldier of love

  • 多倍经验: CF369E Valera and Queries

  • 正难则反,考虑统计不包含组中任意一个给定点的段数,划分成 \(k\) 段区间后扫描线维护。

    点击查看代码
    int l[300010],r[300010],x[300010],ans[300010];
    vector<int>c[1000010];
    vector<pair<int,int> >q[1000010];
    struct BIT
    {
    	int c[1000010];
    	void clear()
    	{
    		memset(c,0,sizeof(c));
    	}
    	int lowbit(int x)
    	{
    		return (x&(-x));
    	}
    	void add(int n,int x,int val)
    	{
    		for(int i=x;i<=n;i+=lowbit(i))  c[i]+=val;
    	}
    	int getsum(int x)
    	{
    		int ans=0;
    		for(int i=x;i>=1;i-=lowbit(i))  ans+=c[i];
    		return ans;
    	}
    }T;
    int main()
    {
    // #define Isaac
    #ifdef Isaac
    	freopen("in.in","r",stdin);
    	freopen("out.out","w",stdout);
    #endif
    	int n,m,k,i,j;
    	while(scanf("%d%d",&n,&m)==2)
    	{
    		T.clear();
    		for(i=1;i<=n;i++)  
    		{
    			scanf("%d%d",&l[i],&r[i]);
    			c[l[i]].push_back(r[i]);
    		}
    		for(i=1;i<=m;i++)
    		{
    			scanf("%d",&k);
    			ans[i]=0;
    			x[0]=0;  x[k+1]=1000001;
    			for(j=1;j<=k;j++)  scanf("%d",&x[j]);
    			for(j=1;j<=k+1;j++)
    			{
    				if(x[j]-1>=x[j-1]+1)  q[x[j-1]+1].push_back(make_pair(x[j]-1,i));
    			}
    		}
    		for(i=1000000;i>=1;i--)
    		{
    			for(j=0;j<c[i].size();j++)  T.add(1000000,c[i][j],1);
    			for(j=0;j<q[i].size();j++)  ans[q[i][j].second]+=T.getsum(q[i][j].first);
    			c[i].clear();  q[i].clear();
    		}
    		for(i=1;i<=m;i++)  printf("%d\n",n-ans[i]);
    	}
    	return 0;
    }
    

\(C\) UOJ 637. 【美团杯2021】A. 数据结构

  • 正难则反。观察到 \(x\) 对答案产生贡献当且仅当所有的 \(x\) 都在 \([l,r]\) 内且 \([l,r]\) 中不含有 \(x-1\) 。不妨先假设所有出现过的元素都对所有区间产生 \(+1\) 的贡献,然后维护变化的贡献。

  • 像上题一次性划分成若干段区间后难以进行数颜色,但可以借鉴划分区间的思想,在扫描线的过程中划分并更新答案。

  • \(a_{i}\) 的极长存在区间为 \([st_{a_{i}},ed_{a_{i}}]\) 。对右端点进行扫描线的过程中,考虑维护每个元素会对什么样的询问产生贡献。

  • 针对第二个限制, \(a_{i}\) 会对询问左端点 \(l \in [last_{a_{i}}+1,\min(st_{a_{i}+1},i)]\) 的答案产生 \(+1\) 的贡献。

  • 针对第一个限制,当 \(ed_{a_{i}}=i\) 时, \(a_{i}\) 无法对询问左端点 \(l \in [last_{a_{i}-1}+1,st_{a_{i}}]\) 的询问产生贡献,故减 \(1\)

    点击查看代码
    int a[1000010],st[1000010],ed[1000010],ans[1000010],last[1000010];
    vector<pair<int,int> >q[1000010];
    struct BIT
    {
    	int c[1000010];
    	int lowbit(int x)
    	{
    		return (x&(-x));
    	}
    	void add(int n,int x,int val)
    	{
    		for(int i=x;i<=n;i+=lowbit(i))  c[i]+=val;
    	}
    	void update(int n,int l,int r,int val)
    	{
    		add(n,l,val);  add(n,r+1,-val);
    	}
    	int getsum(int x)
    	{
    		int ans=0;
    		for(int i=x;i>=1;i-=lowbit(i))  ans+=c[i];
    		return ans;
    	}
    }T;
    int main()
    {
    // #define Isaac
    #ifdef Isaac
    	freopen("in.in","r",stdin);
    	freopen("out.out","w",stdout);
    #endif
    	int n,m,sum=0,l,r,i,j;
    	scanf("%d%d",&n,&m);
    	fill(st+0,st+n+2,n+1);
    	for(i=1;i<=n;i++)
    	{
    		scanf("%d",&a[i]);
    		if(st[a[i]]==n+1)
    		{
    			st[a[i]]=i;
    			sum++;
    		}
    		ed[a[i]]=i;
    	}
    	for(i=1;i<=m;i++)
    	{
    		cin>>l>>r;
    		q[r].push_back(make_pair(l,i));
    	}
    	for(i=1;i<=n;i++)
    	{
    		if(ed[a[i]]==i&&last[a[i]-1]+1<=st[a[i]])  T.update(n,last[a[i]-1]+1,st[a[i]],-1);
    		if(ed[a[i]+1]<=i&&last[a[i]]+1<=min(st[a[i]+1],i))  T.update(n,last[a[i]]+1,min(st[a[i]+1],i),1);
    		last[a[i]]=i;
    		for(j=0;j<q[i].size();j++)  ans[q[i][j].second]=T.getsum(q[i][j].first);
    	}
    	for(i=1;i<=m;i++)  cout<<sum+ans[i]<<endl;
    	return 0;
    }
    

\(D\) luogu P3348 [ZJOI2016] 大森林

\(E\) QOJ 8672. 排队

  • 序列离散点值函数复合

    • 插入-标记-回收 常用于解决函数复合问题,需要扫描线和支持全局进行函数操作的数据结构辅助维护。
    • 分别将询问在左右端点各存储一次,然后从左往右进行扫描线。
    • 插入
      • 若当前扫到的 \(i\) 是某个询问的左端点 \(l\) ,则将其对应的 \(x\) 放入数据结构中。
    • 标记
      • 对数据结构进行 \(f_{i}\) 的操作。
    • 回收
      • 若当前扫到的 \(i\) 是某个询问的右端点 \(r\) ,则将其对应的 \(l\) 放入数据结构中的点的答案作为该询问的答案。
      • 需要自顶向下下传所有标记。
    • 为方便代码实现,记录 \(\{ it \}\) 表示第 \(i\) 个询问对应的节点,并记录父亲节点。
  • 函数操作和 [ABC389F] Rated Range 一样做即可,常数较大,多交几发就过了。

    点击查看代码
    int l[1000010],r[1000010],ans[1000010],it[1000010];
    pair<int,int>ql[1000010],qr[1000010];
    struct BST
    {
    	int root,rt_sum;
    	struct FHQ_Treap
    	{
    		int son[2],fa,val,rnd,cnt,siz,lazy;
    	}tree[1000010];
    	#define lson(rt) (tree[rt].son[0])
    	#define rson(rt) (tree[rt].son[1])
    	#define fa(rt) (tree[rt].fa)
    	BST()
    	{
    		rt_sum=0;
    		srand(time(0));
    	}
    	int build_rt(int val)
    	{
    		rt_sum++;
    		lson(rt_sum)=rson(rt_sum)=fa(rt_sum)=tree[rt_sum].lazy=0;
    		tree[rt_sum].val=val;
    		tree[rt_sum].rnd=rand();
    		tree[rt_sum].cnt=tree[rt_sum].siz=1;
    		return rt_sum;
    	}
    	void pushup(int rt)
    	{
    		tree[rt].siz=tree[lson(rt)].siz+tree[rson(rt)].siz+tree[rt].cnt;
    		fa(rt)=0;
    		if(lson(rt)!=0)  fa(lson(rt))=rt;
    		if(rson(rt)!=0)  fa(rson(rt))=rt;
    	}
    	void pushlazy(int rt,int lazy)
    	{
    		tree[rt].lazy+=lazy;
    		tree[rt].val+=lazy;
    	}
    	void pushdown(int rt)
    	{
    		pushlazy(lson(rt),tree[rt].lazy);
    		pushlazy(rson(rt),tree[rt].lazy);
    		tree[rt].lazy=0;
    	}
    	void split(int rt,int val,int &x,int &y)
    	{
    		if(rt==0)
    		{
    			x=y=0;
    			return;
    		}
    		pushdown(rt);
    		if(tree[rt].val<=val)
    		{
    			x=rt;
    			split(rson(rt),val,rson(x),y);
    		}
    		else
    		{
    			y=rt;
    			split(lson(rt),val,x,lson(y));
    		}
    		pushup(rt);
    	}
    	int merge(int rt1,int rt2)
    	{
    		if(rt1==0||rt2==0)  return rt1+rt2;
    		pushdown(rt1);  pushdown(rt2);
    		if(tree[rt1].rnd<tree[rt2].rnd)
    		{
    			rson(rt1)=merge(rson(rt1),rt2);
    			pushup(rt1);
    			return rt1;
    		}
    		else
    		{
    			lson(rt2)=merge(rt1,lson(rt2));
    			pushup(rt2);
    			return rt2;
    		}
    	}
    	int insert(int val)
    	{
    		int x,y;
    		split(root,val,x,y);
    		root=merge(merge(x,build_rt(val)),y);
    		return rt_sum;
    	}
    	void update(int l,int r)
    	{
    		int x,y,rt;
    		split(root,r,x,y);
    		split(x,l-1,x,rt);
    		pushlazy(rt,1);
    		root=merge(merge(x,rt),y);
    	}
    	int query(int rt)
    	{
    		int ans=tree[rt].val;
    		for(rt=fa(rt);rt!=0;rt=fa(rt))  ans+=tree[rt].lazy;
    		return ans;
    	}
    }T;
    int main()
    {
    // #define Isaac
    #ifdef Isaac
    	freopen("in.in","r",stdin);
    	freopen("out.out","w",stdout);
    #endif
    	int n,m,x,y,i,j,k;
    	scanf("%d%d",&n,&m);
    	for(i=1;i<=n;i++)  scanf("%d%d",&l[i],&r[i]);
    	for(i=1;i<=m;i++)
    	{
    		scanf("%d%d",&x,&y);
    		ql[i]=make_pair(x,i);
    		qr[i]=make_pair(y,i);
    	}
    	sort(ql+1,ql+1+m);  sort(qr+1,qr+1+m);
    	for(i=j=k=1;i<=n;i++)
    	{
    		for(;ql[j].first==i;j++)  it[ql[j].second]=T.insert(0);
    		T.update(l[i],r[i]);
    		for(;qr[k].first==i;k++)  ans[qr[k].second]=T.query(it[qr[k].second]);
    	}
    	for(i=1;i<=m;i++)  printf("%d\n",ans[i]);
    	return 0;
    }
    

\(F\) luogu P9999 [Ynoi2000] tmostnrq

\(G\) luogu P8264 [Ynoi Easy Round 2020] TEST_100

  • 序列函数复合

    • 因为有强制在线的限制,可能会有 \(O(n^{2}V)\) 种不同的询问,此时不能只维护少数点值,而需要维护所有点值的函数复合结果。
    • 可以考虑对序列进行分治,在分治结构上维护区间函数复合后的结果。
    • 对分治结构拆出的每个子问题,预处理全局函数复合后的结果。查询的时候按顺序将 \(x\) 变成 \(x\) 在这些子问题上的全局函数复合的结果。
  • 本题中因 \(n,V\) 同阶,不妨考虑分块。设 \(f_{i,j}\) 表示 \(j\) 经过第 \(i\) 个块后的值。

  • 预处理时需要 \(FHQ-Treap\) 有交合并。实际实现时可以不每次重构整棵树而是复制一个空版本或使用 OI-Wiki 中的方法。

    点击查看代码
    int a[100010],f[50][100010],L[100010],R[100010],pos[100010],it[100010],ans[100010],klen,ksum;
    mt19937 rng(random_device{}());
    struct BST
    {
    	int id[100010],root,rt_sum;
    	struct FHQ_Treap
    	{
    		int son[2],fa,rnd,cnt,siz,val,mn,mx,add,rev;
    	}tree[100010];
    	#define lson(rt) (tree[rt].son[0])
    	#define rson(rt) (tree[rt].son[1])
    	#define fa(rt) (tree[rt].fa)
    	int find(int x)
    	{
    		return id[x]==x?x:id[x]=find(id[x]);
    	}
    	int build_rt(int val)
    	{
    		rt_sum++;  int rt=rt_sum;
    		lson(rt)=rson(rt)=fa(rt)=tree[rt].add=tree[rt].rev=0;
    		tree[rt].val=tree[rt].mn=tree[rt].mx=val;
    		tree[rt].rnd=rng();
    		tree[rt].cnt=tree[rt].siz=1;
    		return id[rt]=rt;
    	}
    	void pushup(int rt)
    	{
    		tree[rt].siz=tree[lson(rt)].siz+tree[rson(rt)].siz+tree[rt].cnt;
    		fa(rt)=0;
    		if(lson(rt)!=0)
    		{
    			tree[rt].mn=tree[lson(rt)].mn;
    			fa(lson(rt))=rt;
    		}
    		else  tree[rt].mn=tree[rt].val;
    		if(rson(rt)!=0)
    		{
    			tree[rt].mx=tree[rson(rt)].mx;
    			fa(rson(rt))=rt;
    		}
    		else  tree[rt].mx=tree[rt].val;
    	}
    	void pushlazy(int rt,int add,int rev)
    	{
    		if(rt==0)  return;
    		if(rev==1)
    		{
    			tree[rt].rev^=1;
    			tree[rt].add=-tree[rt].add+add;  tree[rt].val=-tree[rt].val+add;
    			tree[rt].mn=-tree[rt].mn+add;  tree[rt].mx=-tree[rt].mx+add;
    			swap(tree[rt].mn,tree[rt].mx);
    		}
    		else
    		{
    			tree[rt].add+=add;  tree[rt].val+=add;
    			tree[rt].mn+=add;  tree[rt].mx+=add;
    		}
    	}
    	void pushdown(int rt)
    	{
    		if(tree[rt].rev==1)  swap(lson(rt),rson(rt));
    		pushlazy(lson(rt),tree[rt].add,tree[rt].rev);
    		pushlazy(rson(rt),tree[rt].add,tree[rt].rev);
    		tree[rt].add=tree[rt].rev=0;
    	}
    	void split(int rt,int val,int &x,int &y)
    	{
    		if(rt==0)
    		{
    			x=y=0;
    			return;
    		}
    		pushdown(rt);
    		if(tree[rt].val<=val)
    		{
    			x=rt;
    			split(rson(rt),val,rson(x),y);
    		}
    		else
    		{
    			y=rt;
    			split(lson(rt),val,x,lson(y));
    		}
    		pushup(rt);
    	}
    	int merge(int rt1,int rt2)
    	{
    		if(rt1==0||rt2==0)  return rt1+rt2;
    		pushdown(rt1);  pushdown(rt2);
    		if(tree[rt1].rnd<tree[rt2].rnd)
    		{
    			rson(rt1)=merge(rson(rt1),rt2);
    			pushup(rt1);
    			return rt1;
    		}
    		else
    		{
    			lson(rt2)=merge(rt1,lson(rt2));
    			pushup(rt2);
    			return rt2;
    		}
    	}
    	int join(int rt1,int rt2)
    	{
    		if(rt1==0||rt2==0)  return rt1+rt2;
    		if(tree[rt1].mn>tree[rt2].mx)  return merge(rt2,rt1);
    		if(tree[rt1].mx<tree[rt2].mn)  return merge(rt1,rt2);
    		if(tree[rt1].rnd>tree[rt2].rnd)  swap(rt1,rt2);
    		pushdown(rt1);  pushdown(rt2);
    		int x,y,z;
    		split(rt2,tree[rt1].val,x,y);  split(x,tree[rt1].val-1,x,z);
    		if(z!=0)
    		{
    			tree[rt1].cnt+=tree[z].siz;  tree[rt1].siz+=tree[z].siz;
    			id[z]=rt1;
    		}
    		lson(rt1)=join(lson(rt1),x);  rson(rt1)=join(rson(rt1),y);
    		pushup(rt1);
    		return rt1;
    	}
    	void build()
    	{
    		rt_sum=root=0;
    		for(int i=0;i<=100000;i++)
    		{
    			it[i]=build_rt(i);
    			root=merge(root,i);
    		}
    	}
    	void update(int val)
    	{
    		int x,y;
    		split(root,val,x,y);
    		pushlazy(y,-val,0);  pushlazy(x,val,1);
    		root=join(x,y);
    	}
    	void dfs(int rt)
    	{
    		if(rt==0)  return; 
    		ans[rt]=tree[rt].val;
    		pushdown(rt);
    		dfs(lson(rt));  dfs(rson(rt));
    	}
    }T;
    void init(int n)
    {
    	klen=3000;  ksum=n/klen;
    	for(int i=1;i<=ksum;i++)
    	{
    		L[i]=R[i-1]+1;  R[i]=R[i-1]+klen;
    	}
    	if(R[ksum]<n)
    	{
    		ksum++;
    		L[ksum]=R[ksum-1]+1;  R[ksum]=n;
    	}
    	for(int i=1;i<=ksum;i++)
    	{
    		T.build();
    		for(int j=L[i];j<=R[i];j++)
    		{
    			pos[j]=i;  T.update(a[j]);
    		}
    		T.dfs(T.root);
    		for(int j=0;j<=100000;j++)  f[i][j]=ans[T.find(it[j])];
    	}
    }
    int query(int l,int r,int x)
    {
    	if(pos[l]==pos[r])  for(int i=l;i<=r;i++)  x=abs(x-a[i]);
    	else
    	{
    		for(int i=l;i<=R[pos[l]];i++)  x=abs(x-a[i]);
    		for(int i=pos[l]+1;i<=pos[r]-1;i++)  x=f[i][x];
    		for(int i=L[pos[r]];i<=r;i++)  x=abs(x-a[i]);
    	}
    	return x;
    }
    int main()
    {
    // #define Isaac
    #ifdef Isaac
    	freopen("in.in","r",stdin);
    	freopen("out.out","w",stdout);
    #endif
    	int n,m,l,r,x,ans=0,i;
    	scanf("%d%d",&n,&m);
    	for(i=1;i<=n;i++)  scanf("%d",&a[i]);
    	init(n);
    	for(i=1;i<=m;i++)
    	{
    		scanf("%d%d%d",&l,&r,&x);  l^=ans;  r^=ans;  x^=ans;
    		printf("%d\n",ans=query(l,r,x));
    	}
    	return 0;
    }
    

\(H\) CF702F T-Shirts

\(I\) CF1172F Nauuo and Bug

  • \(FHQ-Treap\) 值域有交合并维护。

    点击查看代码
    ll ans[200010];
    int a[1000010],it[200010],p;
    pair<int,int>ql[200010],qr[200010];
    struct BST
    {
    	int root,rt_sum;
    	struct FHQ_Treap
    	{
    		ll val,lazy;
    		int son[2],fa,rnd,cnt,siz;
    	}tree[200010];
    	#define lson(rt) (tree[rt].son[0])
    	#define rson(rt) (tree[rt].son[1])
    	#define fa(rt) (tree[rt].fa)
    	BST()
    	{
    		rt_sum=0;
    		srand(time(0));
    	}
    	int build_rt(int val)
    	{
    		rt_sum++;
    		lson(rt_sum)=rson(rt_sum)=fa(rt_sum)=tree[rt_sum].lazy=0;
    		tree[rt_sum].val=val;
    		tree[rt_sum].rnd=rand();
    		tree[rt_sum].cnt=tree[rt_sum].siz=1;
    		return rt_sum;
    	}
    	void pushup(int rt)
    	{
    		tree[rt].siz=tree[lson(rt)].siz+tree[rson(rt)].siz+tree[rt].cnt;
    		fa(rt)=0;
    		if(lson(rt)!=0)  fa(lson(rt))=rt;
    		if(rson(rt)!=0)  fa(rson(rt))=rt;
    	}
    	void pushlazy(int rt,ll lazy)
    	{
    		tree[rt].lazy+=lazy;
    		tree[rt].val+=lazy;
    	}
    	void pushdown(int rt)
    	{
    		pushlazy(lson(rt),tree[rt].lazy);
    		pushlazy(rson(rt),tree[rt].lazy);
    		tree[rt].lazy=0;
    	}
    	void split(int rt,ll val,int &x,int &y)
    	{
    		if(rt==0)
    		{
    			x=y=0;
    			return;
    		}
    		pushdown(rt);
    		if(tree[rt].val<=val)
    		{
    			x=rt;
    			split(rson(rt),val,rson(x),y);
    		}
    		else
    		{
    			y=rt;
    			split(lson(rt),val,x,lson(y));
    		}
    		pushup(rt);
    	}
    	int merge(int rt1,int rt2)
    	{
    		if(rt1==0||rt2==0)  return rt1+rt2;
    		pushdown(rt1);  pushdown(rt2);
    		if(tree[rt1].rnd<tree[rt2].rnd)
    		{
    			rson(rt1)=merge(rson(rt1),rt2);
    			pushup(rt1);
    			return rt1;
    		}
    		else
    		{
    			lson(rt2)=merge(rt1,lson(rt2));
    			pushup(rt2);
    			return rt2;
    		}
    	}
    	int join(int rt1,int rt2)
    	{
    		if(rt1==0||rt2==0)  return rt1+rt2;
    		int rt=0;
    		for(;rt2!=0;swap(rt1,rt2))
    		{
    			int x=rt2;
    			for(;lson(x)!=0;x=lson(x))  pushdown(x);
    			split(rt1,tree[x].val,x,rt1);
    			rt=merge(rt,x);
    		}
    		rt=merge(rt,rt1);
    		return rt;
    	}
    	int insert(int val)
    	{
    		int x,y;
    		split(root,val,x,y);
    		root=merge(merge(x,build_rt(val)),y);
    		return rt_sum;
    	}
    	void update(int val)
    	{
    		pushlazy(root,val);
    		int x,y;
    		split(root,p-1,x,y);
    		pushlazy(y,-p);
    		root=join(x,y);
    	}
    	ll query(int rt)
    	{
    		ll ans=tree[rt].val;
    		for(rt=fa(rt);rt!=0;rt=fa(rt))  ans+=tree[rt].lazy;
    		return ans;
    	}
    }T;
    int main()
    {
    // #define Isaac
    #ifdef Isaac
    	freopen("in.in","r",stdin);
    	freopen("out.out","w",stdout);
    #endif
    	int n,m,x,y,i,j,k;
    	scanf("%lld%lld%lld",&n,&m,&p);
    	for(i=1;i<=n;i++)  scanf("%lld",&a[i]);
    	for(i=1;i<=m;i++)
    	{
    		scanf("%lld%lld",&x,&y);
    		ql[i]=make_pair(x,i);
    		qr[i]=make_pair(y,i);
    	}
    	sort(ql+1,ql+1+m);  sort(qr+1,qr+1+m);
    	for(i=j=k=1;i<=n;i++)
    	{
    		for(;ql[j].first==i;j++)  it[ql[j].second]=T.insert(0);
    		T.update(a[i]);
    		for(;qr[k].first==i;k++)  ans[qr[k].second]=T.query(it[qr[k].second]);
    	}
    	for(i=1;i<=m;i++)  printf("%lld\n",ans[i]);
    	return 0;
    }
    

\(J\) luogu P10147 [Ynoi1999] 56TP

\(K\) luogu P8337 [Ynoi2004] rsxc

\(L\) luogu P9057 [Ynoi2004] rpfrdtzls

\(M\) luogu P3316 [SDOI2014] 里面还是外面

\(N\) luogu P11370 [Ynoi2024] 堕天作战/虚空处刑

\(O\) luogu P11369 [Ynoi2024] 弥留之国的爱丽丝

\(P\) luogu P11367 [Ynoi2024] 魔法少女网站第二部

\(Q\) luogu P10151 [Ynoi1999] SMV CC-64“蝰蛇”

\(R\) luogu P10150 [Ynoi1999] TS-54

\(S\) luogu P10028 [Ynoi2000] pri

\(T\) luogu P9996 [Ynoi2000] hpi

\(U\) luogu P9337 [Ynoi2001] 冷たい部屋、一人

\(V\) luogu P9062 [Ynoi2002] Adaptive Hsearch&Lsearch

\(W\) CF1100F Ivan and Burgers

posted @ 2025-02-02 20:44  hzoi_Shadow  阅读(272)  评论(1)    收藏  举报
扩大
缩小