题目描述

小$A$把自己之前得到的序列展示给了小$B$,不过这一次,他并不要求小$B$模仿他之前的行为。他给了小$B$一些询问,每个询问都是$l\ r\ x$的形式,要求小$B$数出在序列的第$l$个到第$r$个元素中有多少是不小于$x$的。小$B$很快就算出来了。小$A$很不甘心,于是要求动态修改这个序列......这样,他只要求每次修改后求出所有询问答案的和即可。然而小$B$还是很快就算出来了,小$A$很生气,于是把问题抛给了你。


输入格式

由于一些原因,本题采取一定的方式加密了修改操作。
第一行三个整数$n\ m\ q$,分别表示序列长度、询问个数和修改次数。第二行$n$个正整数描述序列。接下来$m$行每行三个数$l\ r\ x$,表示一次询问。最后$q$行每行两个数$p\ v$,表示把$p\text{^}lastans$这个位置上的数修改成$v\text{^}lastans$(其中$lastans$指上次修改之后的答案,初始即为没有修改过的原序列的询问答案,$\text{^}$为异或符号,$C/C++$中为$\text{^}$,$pascal$中为$xor$)。


输出格式

$q+1$行每行一个整数,第一行表示原序列的所有询问答案之和,后面$q$行表示每次修改之后的序列的所有询问答案之和。


样例

样例输入:

4 2 2
1 4 2 3
2 4 3
1 3 2
6 6
2 7

样例输出:

4
3
4


数据范围与提示

对于$20\%$的数据,$n,m,q\leqslant 100$
对于$40\%$的数据,$n,m,q\leqslant 1,000$
对于$100\%$的数据,$n,m,q\leqslant 100,000$,序列中的数(包括修改后的)
均为正数且不超过$n$,保证数据合法。


题解

先来考虑如何优化暴力,我们每改变一个点,这个点只会给包含它的区间做贡献。

那么,我们考虑如何快速求出每一个点对答案的贡献。

考虑主席树,对于每一个点建立一棵主席树,点的编号为$x$,对于询问的$l$,我们将其$x$点点权$+1$;对于询问的$r$,我们将点$r+1$的$x$点$-1$,表示删掉了这个询问。

预处理的过程只需要继承上一个点的树即可。

对于修改,我们可以先计算出来原来的贡献,将其减去;再计算现在的贡献,加上去即可。

时间复杂度:$\Theta((q+n)\log m)$。

期望得分:$100$分。

实际得分:$100$分。


代码时刻

#include<bits/stdc++.h>
using namespace std;
int n,m,q;
int a[100001];
int root[100001],tr[4000000],ls[4000000],rs[4000000],cnt;
long long ans;
vector<pair<int,int> > question[100001];
void add(int &x,int pre,int l,int r,int w,int k)
{
x=++cnt;
if(l==r)
{
tr[x]=tr[pre]+k;
return;
}
int mid=(l+r)>>1;
if(w<=mid)
{
add(ls[x],ls[pre],l,mid,w,k);
rs[x]=rs[pre];
}
else
{
add(rs[x],rs[pre],mid+1,r,w,k);
ls[x]=ls[pre];
}
tr[x]=tr[ls[x]]+tr[rs[x]];
}
int ask(int x,int l,int r,int L,int R)
{
if(r<L||R<l)return 0;
if(L<=l&&r<=R)return tr[x];
int mid=(l+r)>>1;
return ask(ls[x],l,mid,L,R)+ask(rs[x],mid+1,r,L,R);
}
int main()
{
scanf("%d%d%d",&n,&m,&q);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int i=1;i<=m;i++)
{
int l,r,x;
scanf("%d%d%d",&l,&r,&x);
question[l].push_back(make_pair(x,1));
question[r+1].push_back(make_pair(x,-1));
}
for(int i=1;i<=n;i++)
{
root[i]=root[i-1];
for(int j=0;j<question[i].size();j++)
add(root[i],root[i],0,n,question[i][j].first,question[i][j].second);
ans+=ask(root[i],0,n,0,a[i]);
}
printf("%lld\n",ans);
while(q--)
{
int p,v;scanf("%d%d",&p,&v);
p^=ans;v^=ans;
ans-=ask(root[p],0,n,0,a[p]);
ans+=ask(root[p],0,n,0,v);
a[p]=v;
printf("%lld\n",ans);
}
return 0;
}

rp++

最新文章

  1. [LeetCode] Game of Life 生命游戏
  2. POJ1717 Dominoes[背包DP]
  3. MySQL5.6安装步骤
  4. iOS7.0后隐藏状态栏(UIStatusBar)
  5. windows  远程桌面命令 mstsc
  6. selenium By.xpath 用法
  7. 从TP、FP、TN、FN到ROC曲线、miss rate、行人检测评估
  8. 关于 屏幕阅读器 和 sr-only
  9. System.IO.StreamWriter
  10. 退役笔记一#MySQL = lambda sql : sql + &amp;#39; Source Code 4 Explain Plan &amp;#39;
  11. Struts2 拦截器具体配置过程
  12. 怎样配置nginx同一时候执行不同版本号的php-fpm
  13. Android集成ffmpeg
  14. CF集萃2
  15. EffectiveC++ 第5章 实现
  16. 非常可乐 HDU1495
  17. ActiveMQ整合spring、同步索引库
  18. T-Sql常用语句
  19. 备忘录:在alpine上安装kvm
  20. qt QTcpServer与QTcpSocket通讯

热门文章

  1. 给url添加时间戳,解决浏览器缓存
  2. Step-by-step from Markov Process to Markov Decision Process
  3. oracle函数与存储方法
  4. 《JAVA设计模式》之模板模式(Template)
  5. JS对像和数组的遍历
  6. Jmeter JAVA请求入门
  7. 基于Idea从零搭建一个最简单的vue项目
  8. JVM(18)之 Class文件
  9. android 好的源码链接
  10. k3 cloud中库存转移处理